基于在视图模型中解析的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));
        }
    }
}

再次感谢您抽出时间

基于在视图模型中解析的xml,将元素动态添加到视图中

我使用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>

这达到了我想要的效果,但比我最初想象的要干净得多。

我希望其他人能明白这番咒骂。如果没有,请随时向我提问。我会尽我所能详细说明。