基于在视图模型中解析的xml,将元素动态添加到视图中
本文关键字:视图 元素 动态 添加 xml 模型 | 更新日期: 2023-09-27 18:28:41
Hallo,感谢您抽出时间。
我正在为学校做一个项目,周末遇到了一个我想解决的问题。(我的老师显然不能回答问题)
我正在为我的应用程序使用MVVM架构。我希望根据我在ViewModel 中的相关XML文件中找到的所选类别的条目数量,将堆叠面板(带有一些内容)动态添加到视图中
我创建了一个XMLContainer类,它使用了singleton模式。我有一个名为"Categories"的枚举,其中包含可用的类别。我有一个名为"SecondPageViewModel"的ViewModel
我只做了两个月,所以即使你认为你的意思很明显。请详细说明:)
我的工具:Visual Studio Ultimate 2013Resharper 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));
}
}
}
再次感谢您抽出时间
我使用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的Grid元素的第一个打开标记处,我设置了DataContext,如下所示
<Grid.DataContext>
<ViewModel:SecondPageViewModel/>
</Grid.DataContext>
这达到了我想要的效果,但比我最初想象的要干净得多。
我希望其他人能明白这番咒骂。如果没有,请随时向我提问。我会尽我所能详细说明。