c# - 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>
任何帮助将不胜感激,谢谢
解决方案
我开发了一个用于序列化的类,并给它一个 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);
}
推荐阅读
- html-email - html-emails - 如果我添加图像,电子邮件发送将不起作用
- sql - 从 2 个 case 语句中相互扣除值
- azure-data-factory - Storage Accoung V2 访问防火墙,VNET 到数据工厂 V2
- sql - sql中firebase的集合和文档的等价物是什么?
- apache-spark - 有没有办法在 spark 提交中使用 spark 提供的 hdfs 委托令牌用于其他 hdfs 连接?
- swift - 视图不会在 foreach 中重新加载
- javascript - 使用 D3 解决 Promise
- java - 如何用 REST API URL 解决两个连续的斜线?
- php - 无法在 php docker 映像中启用 ldap 扩展
- c++ - 将一个 QByteArray 附加到另一个 QByteArray