2014-10-31 54 views
0

你好,感謝你的時間。動態添加元素來查看基於xml解析的viewmodel

我正在爲學校製作一個項目,而且我遇到了一個id想要在週末解決的問題。 (我的老師顯然沒有問題)

我正在爲我的應用程序使用MVVM架構。 我希望動態地添加堆棧面板(有一些內容)的視圖,基於多少條目的選定的類別,我發現在相關的XML文件中的ViewModel我已經創建了一個XMLContainer類,它使用單身模式。 我有一個名爲「類別」與可用類別的枚舉。 我有一個ViewModel叫'SecondPageViewModel'

我只有這樣做了2個月,所以即使你認爲它明顯是什麼意思。詳細一點更請:)

我的工具: Visual Studio的終極2013 ReSharper的8

分類枚舉:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace TouristAppV3.Enums 
{ 
    enum Categories 
    { 
     Bars, 
     Festivals, 
     Hotels, 
     Museums, 
     Restaurants, 
    } 

} 

XMLContainer類:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Xml.Linq; 
using Windows.ApplicationModel; 
using Windows.Media.MediaProperties; 
using Windows.Storage; 
using TouristAppV3.Enums; 

namespace TouristAppV3.Classes 
{ 
    /// <summary> 
    /// This class uses the singleton pattern. 
    /// Use GetInstance() to use the class 
    /// </summary> 
    class XMLContainer 
    { 
     private static XMLContainer _object; 
     private IEnumerable<XElement> BarsXML; 
     private IEnumerable<XElement> HotelsXML; 
     private IEnumerable<XElement> MuseumsXML; 
     private IEnumerable<XElement> RestaurantsXML; 
     private IEnumerable<XElement> FestivalsXML; 

     private XMLContainer() 
     { 
      GetBars(); 
      GetFestivals(); 
      GetHotels(); 
      GetMuseums(); 
      GetRestaurants(); 
     } 

     /// <summary> 
     /// Usage: XMLContainer "desired name" = XMLContainer.GetInstance() 
     /// </summary> 
     /// <returns>The same object every time.</returns> 
     public static XMLContainer GetInstance() 
     { 
      if (_object == null) 
      { 
       _object = new XMLContainer(); 
      } 
      return _object; 
     } 


     /// <summary> 
     /// Returns the XML for the requested category 
     /// </summary> 
     /// <param name="desiredCategory">The desired category</param> 
     /// <returns>ienumerable xelement</returns> 
     public IEnumerable<XElement> ReturnXMLFrom(Categories desiredCategory) 
     { 
      switch (desiredCategory) 
      { 
       case Categories.Bars: 
        return BarsXML; 
       case Categories.Hotels: 
        return HotelsXML; 
       case Categories.Festivals: 
        return FestivalsXML; 
       case Categories.Museums: 
        return MuseumsXML; 
       case Categories.Restaurants: 
        return RestaurantsXML; 
      } 
      return null; 
     } 

     private void GetBars() 
     { 
      GetXML(Categories.Bars); 
     } 

     private void GetHotels() 
     { 
      GetXML(Categories.Hotels); 
     } 

     private void GetMuseums() 
     { 
      GetXML(Categories.Museums); 
     } 

     private void GetRestaurants() 
     { 
      GetXML(Categories.Restaurants); 
     } 

     private void GetFestivals() 
     { 
      GetXML(Categories.Festivals); 
     } 

     /// <summary> 
     /// Gets the content of the xml file associated with the selected category 
     /// </summary> 
     /// <param name="selectedCategory"></param> 
     private async void GetXML(Categories selectedCategory) 
     { 
      string _selectedCategory = selectedCategory.ToString(); 
      StorageFile categoryFile = null; 

      StorageFolder installationFolder = Package.Current.InstalledLocation; 
      string xmlPath = @"Assets\xml\Models\" + _selectedCategory + ".xml"; 
      categoryFile = await installationFolder.GetFileAsync(xmlPath); 

      Stream categoryStream = await categoryFile.OpenStreamForReadAsync(); 
      XDocument categoryXDocument = XDocument.Load(categoryStream); 
      categoryStream.Dispose(); 
      IEnumerable<XElement> returnThis = categoryXDocument.Descendants(_selectedCategory.Remove(_selectedCategory.Count() - 1).ToLower()); 
      switch (_selectedCategory) 
      { 
       case "Bars": 
        BarsXML = returnThis; 
        break; 
       case "Hotels": 
        HotelsXML = returnThis; 
        break; 
       case "Restaurants": 
        RestaurantsXML = returnThis; 
        break; 
       case "Museums": 
        MuseumsXML = returnThis; 
        break; 
       case "Festivals": 
        FestivalsXML = returnThis; 
        break; 
      } 

     } 

    } 
} 

SecondPageViewModel:

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Collections.Specialized; 
using System.ComponentModel; 
using System.IO; 
using System.Linq; 
using System.Runtime.CompilerServices; 
using System.Text; 
using System.Threading.Tasks; 
using System.Xml; 
using System.Xml.Linq; 
using Windows.ApplicationModel; 
using Windows.Storage; 
using Windows.UI.Core; 
using TouristAppV3.Annotations; 
using TouristAppV3.Classes; 
using TouristAppV3.Enums; 

namespace TouristAppV3.ViewModel 
{ 
    class SecondPageViewModel : INotifyPropertyChanged 
    { 
     private IEnumerable<XElement> xml; 
     private string _selectedCategory = MainPageViewModel.SelectedCategory; 


     public SecondPageViewModel() 
     { 
      LoadXML(); 
     } 

     private void LoadXML() 
     { 
      XMLContainer xmlContainer = XMLContainer.GetInstance(); 
      switch (_selectedCategory) 
      { 
       case "Bars": 
        xml = xmlContainer.ReturnXMLFrom(Categories.Bars); 
        break; 
       case "Hotels": 
        xml = xmlContainer.ReturnXMLFrom(Categories.Hotels); 
        break; 
       case "Restaurants": 
        xml = xmlContainer.ReturnXMLFrom(Categories.Restaurants); 
        break; 
       case "Museums": 
        xml = xmlContainer.ReturnXMLFrom(Categories.Museums); 
        break; 
       case "Festivals": 
        xml = xmlContainer.ReturnXMLFrom(Categories.Festivals); 
        break; 
      } 

     } 


     public event PropertyChangedEventHandler PropertyChanged; 

     [NotifyPropertyChangedInvocator] 
     protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
     { 
      PropertyChangedEventHandler handler = PropertyChanged; 
      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

再一次,謝謝你的時間

+0

將XML反序列化爲POCO,這些是您的模型。將它們存儲在虛擬機的屬性中。綁定你的用戶界面到這些,使用DataTemplates顯示對應於每種類型的用戶界面。現在你已經完成了。 – Will 2014-10-31 15:00:02

+0

我解決了數據綁定到GridView元素的問題。我喜歡發佈我的代碼供他人閱讀。但我沒有選擇添加答案 – 2014-10-31 21:17:58

回答

0

我解決了我的問題,使用GridView。 爲GridView元素的更多細節,在這裏讀到:http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh780650.aspx

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview%28v=vs.110%29.aspx

這是我實現我想出了一個解決方案。

成品SecondPageViewModel:

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Collections.Specialized; 
using System.ComponentModel; 
using System.IO; 
using System.Linq; 
using System.Runtime.CompilerServices; 
using System.Text; 
using System.Threading.Tasks; 
using System.Xml; 
using System.Xml.Linq; 
using Windows.ApplicationModel; 
using Windows.Storage; 
using Windows.UI.Core; 
using TouristAppV3.Annotations; 
using TouristAppV3.Classes; 
using TouristAppV3.Enums; 
using TouristAppV3.Model; 

namespace TouristAppV3.ViewModel 
{ 
    class SecondPageViewModel : INotifyPropertyChanged 
    { 
     #region Fields 
     private IEnumerable<XElement> xml; 
     private string _selectedCategory = MainPageViewModel.SelectedCategory; 
     private string _xmlElementOfInterrest = "type"; 
     private ObservableCollection<GenericModel> _places; 

     #endregion 

     #region Constructor 
     public SecondPageViewModel() 
     { 
      LoadXML(); 
      Places = new ObservableCollection<GenericModel>(); 
      PopulatePlaces(); 
     } 


     #endregion 

     #region Methods 
     /// <summary> 
     /// Loads xml for _selectedCategory 
     /// </summary> 
     private void LoadXML() 
     { 
      XMLContainer xmlContainer = XMLContainer.GetInstance(); 
      switch (_selectedCategory) 
      { 
       case "Bars": 
        xml = xmlContainer.ReturnXMLFrom(Categories.Bars); 
        break; 
       case "Hotels": 
        xml = xmlContainer.ReturnXMLFrom(Categories.Hotels); 
        break; 
       case "Restaurants": 
        xml = xmlContainer.ReturnXMLFrom(Categories.Restaurants); 
        break; 
       case "Museums": 
        xml = xmlContainer.ReturnXMLFrom(Categories.Museums); 
        break; 
       case "Festivals": 
        xml = xmlContainer.ReturnXMLFrom(Categories.Festivals); 
        break; 
      } 

     } 

     private void PopulatePlaces() 
     { 
      if (_selectedCategory == Categories.Bars.ToString() || 
       _selectedCategory == Categories.Hotels.ToString() || 
       _selectedCategory == Categories.Museums.ToString() || 
       _selectedCategory == Categories.Restaurants.ToString()) 
      { 
       if (_selectedCategory == Categories.Hotels.ToString()) 
       { 
        _xmlElementOfInterrest = "quality"; 
       } 
       if (_selectedCategory == Categories.Museums.ToString()) 
       { 
        _xmlElementOfInterrest = "subtitle"; 
       } 
      } 
      try 
      { 
       foreach (XElement place in xml) 
       { 
        string name = place.Attribute("name").Value; 
        string subtitle = place.Element(_xmlElementOfInterrest).Value; 
        string imagePath = place.Element("imageURL").Value; 
        Places.Add(new GenericModel(name, subtitle, _selectedCategory, imagePath)); 
       } 
      } 
      catch (Exception) 
      { 
      } 
     } 

     #endregion 

     #region Properties 

     public string PageName 
     { 
      get { return _selectedCategory; } 
      private set { _selectedCategory = value; } 
     } 

     public ObservableCollection<GenericModel> Places 
     { 
      get { return _places; } 
      set { _places = value; } 
     } 

     #endregion 

     #region OnPropertyChanged method 
     public event PropertyChangedEventHandler PropertyChanged; 

     [NotifyPropertyChangedInvocator] 
     protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
     { 
      PropertyChangedEventHandler handler = PropertyChanged; 
      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
     #endregion 
    } 
} 

觀的GridView的一部分:

<GridView x:Name="gridview_items" 
      Grid.Row="1" 
      ItemsSource="{Binding Places, Mode=TwoWay}" 
      IsItemClickEnabled="True" 
      ItemClick="ItemView_ItemClick"> 
    <GridView.ItemsPanel> 
     <ItemsPanelTemplate> 
      <WrapGrid Orientation="Horizontal" MaximumRowsOrColumns="4"/> 
     </ItemsPanelTemplate> 
    </GridView.ItemsPanel> 
    <GridView.ItemTemplate> 
     <DataTemplate> 
      <Grid HorizontalAlignment="Left" Width="331" Height="200"> 
       <Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}"> 
        <Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Name}"/> 
       </Border> 
       <StackPanel VerticalAlignment="Bottom" Background="{ThemeResource ListViewItemOverlayBackgroundThemeBrush}"> 
        <TextBlock Text="{Binding Name}" Foreground="{ThemeResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextBlockStyle}" Height="60"/> 
        <TextBlock Text="{Binding Subtitle}" Foreground="{ThemeResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap"/> 
       </StackPanel> 
      </Grid> 
     </DataTemplate> 
    </GridView.ItemTemplate> 
</GridView> 

在含有該GridView的網格元件的第一開口標籤,我設置在DataContext,像這樣。

<Grid.DataContext> 
    <ViewModel:SecondPageViewModel/> 
</Grid.DataContext> 

這實現了我想要的效果,但是以比我原本想的更清潔的方式。

我希望這種消除對其他人是清楚的。如果沒有,請隨時向我提問。我會盡我所能詳細說明。