首页 > 解决方案 > WPF MVVM 结构中数据源的 XML

问题描述

我在设计 WPF 应用程序时正在学习 MVVM 模式。到目前为止,我正在阅读一个非常好的教程,但是它们的模型数据正在我的 ViewModel 的构造函数中填充。在本教程中提到,在现实世界中,数据将由数据库或 XML 文件提供。我真的很想知道如何使用 XML 文件来填充模型数据,因为我讨厌在我的代码中包含硬编码的值。

这是我的模型

namespace MVVM_Basics.Models
{
    using System;
    using System.ComponentModel;
    //need to implement the interface INotifyPropertyChange, because this is how WPF does it's data binding.
    public class Customer : INotifyPropertyChanged
    {
        /// <summary>
        /// Initializing a new instance of the Customer class
        /// </summary>
        //this is a default constructor for the Customer class
        public Customer(String customerName)
        {
            Name = customerName;
        }

        private string _Name;
        /// <summary>
        /// Gets or Sets the Customers Name
        /// </summary>
        public String Name
        {
            get{ return _Name;}
            set 
            {
                _Name = value;
                OnPropertyChanged("Name");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName) 
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null) 
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

这是视图模型

using MVVM_Basics.Commands;
using MVVM_Basics.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace MVVM_Basics.ViewModels
{
    internal class CustomerViewModel
    {
        /// <summary>
        /// Initializes a new instance of the CustomerViewModel class
        /// </summary>

        //creating the constructor for the class
        //setting a Name to a Customer instance
        //initializing the UpdateCommand with command we created in the CustomerUpdateCOmmand class, the constructor takes in a ViewModel and since we are
        //creating it here, we can reference CustomerViewModel by using the 'this' keyword. 
        public CustomerViewModel()
        {
            _Customer = new Customer("David"); //this is the hard coded value that I would like to be populated with a XML file
            UpdateCommand = new CustomerUpdateCommand(this);
        }

        /// <summary>
        /// Gets or Sets a Boolean value to indicating whether the Customer can be updated
        /// </summary>
        public bool CanUpdate 
        {
            get
            {
                if(Customer == null)
                {
                    return false;
                }
                return !String.IsNullOrWhiteSpace(Customer.Name);
            } 

        }
        //without adding logic to CanUpdate, the button that it is binding to will always be disabled because the default value for a boolean is false
        //we added logic that only returned false if there was not a name in the text box.

        /// <summary>
        /// creates an instance of a Customer
        /// </summary>
        private Customer _Customer;
        public Customer Customer
        {
            get{ return _Customer; }
        }

        /// <summary>
        /// Gets the UpdateCommand for the ViewModel
        /// </summary>
        public ICommand UpdateCommand
        {
            get;
            private set;
        }

        /// <summary>
        /// Saves changes made to the Customer instance
        /// </summary>
        public void SaveChanges()
        {
            //because this is just a simple demo I am using the Debug property to display dialog. Normally this would save back to your actual dataset
            Debug.Assert(false, String.Format("{0} was updated.", Customer.Name));
        } 

    }
}

这是视图

<Window x:Class="MVVM_Basics.Views.CustomerView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MVVM_Basics.Views"
        mc:Ignorable="d"
        Title="Customer Update" Height="350" Width="520">

    <Grid VerticalAlignment="Top" Margin="15">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>


        <Label Grid.Column="0" Content="Customer Name" />
        <TextBox Grid.Column="1" Text="{Binding Customer.Name, UpdateSourceTrigger=PropertyChanged}"  />
        <Button Grid.Column="2" Command="{Binding UpdateCommand}" Content="Update" />

    </Grid>

</Window>

任何帮助将不胜感激,谢谢

标签: c#wpfmvvm

解决方案


我开发了一个用于序列化的类,并给它一个 Deserialize 方法和一个 Serialize 方法

namespace MVVM_Basics.Commands
{
    //the following class is used to retrieve data that is in an XML document. The document is name Customer.xml and is located in the data folder.
    //We are using the Deserialize feature to grab info needed from the XML doc and then data bind it to parts of a View through that View's ViewModel
    public class Serializer
    {
        /// <summary>
        /// populate a class with xml data 
        /// </summary>
        /// <typeparam name="T">Object Type</typeparam>
        /// <param name="input">xml data</param>
        /// <returns>Object Type</returns>
        public T Deserialize<T>(string input) where T : class
        {
            XmlSerializer ser = new XmlSerializer(typeof(T));

            using (StringReader sr = new StringReader(input))
            {
                return (T)ser.Deserialize(sr);
            }
        }

        /// <summary>
        /// convert object to xml string
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ObjectToSerialize"></param>
        /// <returns></returns>
        public string Serialize<T>(T ObjectToSerialize)
        {
            XmlSerializer xmlSerializer = new XmlSerializer(ObjectToSerialize.GetType());

            using (StringWriter textWriter = new StringWriter())
            {
                xmlSerializer.Serialize(textWriter, ObjectToSerialize);
                return textWriter.ToString();
            }
        }
    }
}

然后在我的 ViewModel 中,我创建了一个客户变量和包含我的 XML 路径的变量。然后我将反序列化的数据应用于创建我的客户对象的客户。

//setting up some variable that will be use through this class
        // the private read only is setting up a Customer data type that will have a customer object attached to it
        private readonly Customer customer;
        string path = Directory.GetCurrentDirectory() + @"\Customer.xml"; 
        string xmlInputData = string.Empty;

        public CustomerViewModel()
        {
            //we are defining that we are using the CustomerUpdateCommand with this ViewModel on construction of 'this' ViewModel
            UpdateCommand = new CustomerUpdateCommand(this);

            //the 'path' variable is the path to the XML file containing all Customer data, we first just check the file does exist, we then create 
            //an instance of the Serializer class and use that class on the XML file using the Deserialize method from the class. Then attached the data to an
            //instance of a Customer object that we created a 'private readonly' variable for. 
            if (File.Exists(path))
            {
                xmlInputData = File.ReadAllText(path);
            }
            Serializer ser = new Serializer();
            customer = ser.Deserialize<Customer>(xmlInputData);


        }

推荐阅读