c# - ViewModel 中的 XML 到 LINQ 以填充模型
问题描述
我有一个要用于填充模型的 XML 文件。I have multiple studies within my XML and my goal is to populate a list with all the study names and when the study name is selected and submit button is pressed then the application will navigate to a new window but carry the rest of the XML data from选定的研究。
XML
<?xml version="1.0" encoding="utf-8" ?>
<Studies>
<Study>
<StudyTitle>SPIROMICS2</StudyTitle>
<ImportDirectory>Z:\SPIROMICS\Human_Scans\Dispatch_Received\NO_BACKUP_DONE_HERE\IMPORT</ImportDirectory>
</Study>
<Study>
<StudyTitle>BLF</StudyTitle>
<ImportDirectory>Z:\BLF\Human Scans\Dispatch Received\IMPORT</ImportDirectory>
</Study>
</Studies>
模型.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DICOM_Importer.Models
{
/// <summary>
/// Model for all active studies within the APPIL lab
/// </summary>
public class Studies : INotifyPropertyChanged, IDataErrorInfo
{
private string studyTitle;
private string importDirectory;
public string StudyTitle
{
get { return studyTitle; }
set
{
studyTitle = value;
OnPropertyChanged("StudyTitle");
}
}
public string ImportDirectory
{
get { return importDirectory; }
set
{
importDirectory = value;
OnPropertyChanged("ImportDirectory");
}
}
#region PropertyChangedEventHandler
//Create a PropertyChangedEventHandler variable that you can use to handle data changing
public event PropertyChangedEventHandler PropertyChanged;
//create the method that will handle the updating of data if a property is changed.
private void OnPropertyChanged(string propertyChanged)
{
//bring in the event handler variable that you created and assign it to this methods 'handler' variable
PropertyChangedEventHandler handler = PropertyChanged;
//if the the handler is not null, which means the property has been changed, then hand in the new value to the handler to be changed
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyChanged));
}
}
#endregion
#region DataErrorInfo
/// <summary>
/// Getter and Setter for the Error message that we setup through the IDataErrorInfo interface
/// </summary>
public string Error
{
get;
set;
}
//the column name passed in will be a property on the Studies Object that we want to validate
//this validatation is looking at the StudyTitle property. If the StudyTitle property is 'null' or just white space then we are going to add the error message
//"Study Title cannot be null or empty" Otherwise if StudyTitle is fine the error message will be 'null'
public string this[string columnName]
{
get
{
if (columnName == "StudyTitle")
{
if (String.IsNullOrWhiteSpace(StudyTitle))
{
Error = "Study Title cannot be null or empty";
}
else
{
Error = null;
}
}
return Error;
}
}
#endregion
}
}
视图模型.cs
using DICOM_Importer.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace DICOM_Importer.ViewModels
{
internal class HomeViewModel
{
//setting up some variable that will be use through this class
// the private read only is setting up a Studies data type that will have a studies object attached to it
private readonly Studies studies;
public string studyTitle;
/// <summary>
/// Initializes a new instance of the CustomerViewModel class
/// </summary>
public HomeViewModel()
{
string path_to_debug_folder = Directory.GetCurrentDirectory();
string path = Path.GetFullPath(Path.Combine(path_to_debug_folder, @"..\..\")) + @"Data\Studies.xml";
//the 'path' variable is the path to the XML file containing all Studies 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 Studies object that we created a 'private readonly' variable for.
if (File.Exists(path))
{
XElement xe = XElement.Load(path);
var x = xe.Elements();
foreach (var tag in x)
{
studyTitle = tag.FirstNode.ToString();
}
}
}
/// <summary>
/// creates an instance of a Customer
/// </summary>
public Studies Studies
{
get { return studies; }
}
}
}
视图.xaml
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:DICOM_Importer.Views"
mc:Ignorable="d"
Background="Gold"
Title="DICOM Importer" Height="385" Width="600">
<Grid Style="{StaticResource gridBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Column="1" Grid.Row="0" Style="{StaticResource homeTitle}">DICOM IMPORTER</Label>
<Image x:Name="appil_logo" Grid.Column="0" Grid.Row="0" Grid.RowSpan="4" Source="/assets/appil_logo.png"/>
<Border Grid.Column="1" Grid.Row="0" Style="{StaticResource studyListHeader}" Width="Auto">
<Label Style="{StaticResource studyListText}">Active Studies</Label>
</Border>
<ListBox Name="activeStudiesListBox" Grid.Column="1" Grid.Row="2" >
<Label Content="{Binding Studies.StudyTitle}" />
</ListBox>
<Button Grid.Row="3" Grid.Column="1" Style="{StaticResource buttonStyle}">Select</Button>
</Grid>
</Window>
我知道我的 ViewModel 不正确,这主要是我的问题所在。谁能告诉我如何使用这个 XML 文件和模型在我的视图中使用 studyTitle 填充我的列表框。我希望能够向 XML 文件添加一项新研究,并将其包含在视图的列表框中。
解决方案
由于您的模型类的名称在Studies
某种程度上令人讨厌(因为它映射到Study
XML 对象),所以我将其重命名为Study
.
我还建议实施INotifyDataErrorInfo
替代(示例)。它取代了旧的一个过时的IDataErrorInfo
。
视图模型.cs
// If proeprty values are expected to change
// and this changes are required to propagate to the view
// this class must implement INotifyPropertyChanged
public class ViewModel
{
private void ReadXml(string filePath)
{
var xmlRootElement = XElement.Load(path);
List<Studies> studies = xmlRootElement.Decendants("Study")
.Select(CreateModelFromStudyXmlNode)
.ToList();
this.Studies = new ObservableCollection<Study>(studies);
}
private Study CreateModelFromStudyXmlNode(XElement studyXmlNode)
{
var newStudy = new Study();
newStudy.StudyTitle = studyXmlNode.Element("StudyTitle").Value;
newStudy.ImportDirectory = studyXmlNode.Element("ImportDirectory").Value;
return newStudy;
}
public ObservableCollection<Study> Studies { get; set; }
}
研究.cs
public class Study
{
public string StudyTitle { get; set; }
public string ImportDirectory { get; set; }
}
主窗口.xaml
<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<ListBox ItemsSource="{Binding Studies}" >
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type Study}">
<TextBlock Text="{Binding StudyTitle}" />
</DataTemplate>
<ListBox.ItemTemplate>
</ListBox>
</Window>
推荐阅读
- reactjs - 呈现特定于 onLongPress 的视图的消息问题
- python - Python Celery 任务优先级未按预期工作
- mongodb - 在 mongodb 中查找后无法访问日期值
- apache-superset - 安装超集:“superset db upgrade”退出,代码为 132
- java - Elastic Spring Data 还是 Java 高级 REST 客户端?
- c# - C# 使用加密密码进行电子邮件 Ssl 身份验证
- javascript - 仅更改 React 中输入字段的前两个数字
- java - 发布请求没有参数
- node.js - 如何在没有数据建模的情况下在猫鼬中 CRUD 数据
- java - 将方法的现有代码包装在 try-finally 块中