根据viewmodel中解析的xml动态添加要查看的元素

时间:2014-10-31 14:08:12

标签: c# mvvm windows-store-apps

你好,谢谢你的时间。

我正在为学校制作一个项目,我遇到了一个想在周末解决的问题。 (我的老师显然无法提问)

我正在为我的应用程序使用MVVM架构。 我希望根据我在ViewModel中关联的XML文件中找到的所选类别的条目数量,动态地将stackpanels(包含一些内容)添加到View中

我创建了一个XMLContainer类,它使用单例模式。 我有一个名为' Categories'与可用的类别。 我有一个名为' SecondPageViewModel'

的ViewModel

我这样做了2个月,所以即使你认为它的意思很明显。再详细说明一下:)

我的工具: Visual Studio Ultimate 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));
        }
    }
}

再次,谢谢你的时间

1 个答案:

答案 0 :(得分: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
    }
}

View的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>

这实现了我想要的效果,但是比我最初想的要清晰得多。

我希望其他人能够明白这种言论。如果没有,请随时向我提问。我会尽可能详细说明。