2014-10-31 53 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> 

这实现了我想要的效果,但是以比我原本想的更清洁的方式。

我希望这种消除对其他人是清楚的。如果没有,请随时向我提问。我会尽我所能详细说明。