我想制作应用程序,将我的xml文件中的数据反序列化为类结构。我通过'粘贴XML作为类'工具准备了类,但是所有内容都是在公共字段或表上进行的,当我尝试为List或ObservableCollections进行更改时,serializator正确地停止加载xml文档。
我接下来要做的是从树视图中选择一些元素,编辑它,然后再次保存到xml文件。我不想直接在.xml上这样做。 这是我的XML示例:
<plan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="schema.xsd">
<nagłówek>
<autorzy>
<nazwa>Autorzy:</nazwa>
<autor atr="one">
<numer>222</numer>
<imię>Rust</imię>
<nazwisko>Snow</nazwisko>
</autor>
<autor>
<numer>111</numer>
<imię>Ian</imię>
<nazwisko>Nower</nazwisko>
</autor>
</autorzy>
</nagłówek>
...
以下是类
的例子/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class plan
{
private planNagłówek nagłówekField;
private planGłówny głównyField;
/// <remarks/>
public planNagłówek nagłówek
{
get
{
return this.nagłówekField;
}
set
{
this.nagłówekField = value;
}
}
/// <remarks/>
public planGłówny główny
{
get
{
return this.głównyField;
}
set
{
this.głównyField = value;
}
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class planNagłówek
{
private planNagłówekAutorzy autorzyField;
/// <remarks/>
public planNagłówekAutorzy autorzy
{
get
{
return this.autorzyField;
}
set
{
this.autorzyField = value;
}
}
}
以及如何加载xml:
// Create an instance of the XmlSerializer specifying type and namespace.
XmlSerializer serializer = new XmlSerializer(typeof(XML.plan));
// A FileStream is needed to read the XML document.
FileStream fs = new FileStream("...somepath.../Untitled4.xml", FileMode.Open);
XmlReader reader = XmlReader.Create(fs);
// Use the Deserialize method to restore the object's state.
i = (XML.plan)serializer.Deserialize(reader);
fs.Close();
这是我得到的以及我的xml文件,也许这会帮助你帮助我:) https://drive.google.com/file/d/0B0wPodV30rnJSVA1ckVxWldDRDA/view
答案 0 :(得分:1)
要在WPF TreeView
中显示类的层次结构,在XAML中,您需要定义与层次结构中可能包含子项的每种类型相对应的HierarchicalDataTemplate
,以及DataTemplate
对应于层次结构中不具有子项的每种类型的类。每个数据模板应该定义一个框架元素(例如TextBlock
或容器控件,例如DockPanel
,其中包含任意数量的嵌入式框架元素作为子元素),它将显示该类型的数据树中的类,具有适当的绑定。
首先,使用xsd.exe
为您的XML自动生成类。要简单地在树中显示数据,您不需要实施INotifyPropertyChanged
或为儿童使用ObservableCollection<T>
:
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class plan
{
private planNagłówek[] itemsField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("nagłówek", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public planNagłówek[] Items
{
get
{
return this.itemsField;
}
set
{
this.itemsField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class planNagłówek
{
private planNagłówekAutorzy[] autorzyField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("autorzy", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public planNagłówekAutorzy[] autorzy
{
get
{
return this.autorzyField;
}
set
{
this.autorzyField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class planNagłówekAutorzy
{
private string nazwaField;
private planNagłówekAutorzyAutor[] autorField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string nazwa
{
get
{
return this.nazwaField;
}
set
{
this.nazwaField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("autor", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public planNagłówekAutorzyAutor[] autor
{
get
{
return this.autorField;
}
set
{
this.autorField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class planNagłówekAutorzyAutor
{
private string numerField;
private string imięField;
private string nazwiskoField;
private string atrField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string numer
{
get
{
return this.numerField;
}
set
{
this.numerField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string imię
{
get
{
return this.imięField;
}
set
{
this.imięField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string nazwisko
{
get
{
return this.nazwiskoField;
}
set
{
this.nazwiskoField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string atr
{
get
{
return this.atrField;
}
set
{
this.atrField = value;
}
}
}
接下来,在XAML中定义一个用户界面,在其中显示这些类,为每个级别手动创建适当的数据模板:
<Window x:Class="WpfTreeViewNew.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:w="clr-namespace:WpfTreeViewNew"
Title="Window1" Height="300" Width="600">
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type w:plan}" ItemsSource="{Binding Path=Items}">
<TextBlock Text="Plan">
</TextBlock>
</HierarchicalDataTemplate >
<HierarchicalDataTemplate DataType="{x:Type w:planNagłówek}" ItemsSource="{Binding Path=autorzy}">
<TextBlock Text="Nagłówek">
</TextBlock>
</HierarchicalDataTemplate >
<HierarchicalDataTemplate DataType="{x:Type w:planNagłówekAutorzy}" ItemsSource="{Binding Path=autor}">
<TextBlock Text="{Binding Path=nazwa}"/>
</HierarchicalDataTemplate >
<DataTemplate DataType="{x:Type w:planNagłówekAutorzyAutor}">
<Border BorderBrush="Gray" BorderThickness="1" MinWidth="300">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="3" Text="{Binding Path=atr}"/>
<TextBlock Margin="3" Text="{Binding Path=numer}"/>
<TextBlock Margin="3" Text="{Binding Path=imię}"/>
<TextBlock Margin="3" Text="{Binding Path=nazwisko}"/>
</StackPanel>
</Border>
</DataTemplate >
</Window.Resources>
<Grid DockPanel.Dock="Bottom">
<TreeView Margin="3" Name="treeView1">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</Grid>
</Window>
最后,以编程方式加载数据,例如在启动时:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
string xml = @"<plan xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:noNamespaceSchemaLocation=""schema.xsd"">
<nagłówek>
<autorzy>
<nazwa>Autorzy:</nazwa>
<autor atr=""one"">
<numer>222</numer>
<imię>Rust</imię>
<nazwisko>Snow</nazwisko>
</autor>
<autor>
<numer>111</numer>
<imię>Ian</imię>
<nazwisko>Nower</nazwisko>
</autor>
</autorzy>
</nagłówek>
</plan>
";
var plan = XmlSerializationHelper.LoadFromXML<plan>(xml);
var xml2 = plan.GetXml();
Debug.WriteLine(xml2); // For testing
var children = new List<plan>();
children.Add(plan);
treeView1.Items.Clear();
treeView1.ItemsSource = children;
}
}
这会产生如下所示的内容:
您需要用更漂亮的东西替换每个模板。
老实说,在完成所有这些之后,我现在相信WinForms树may be easier to work with。
更新 - 修改
重新阅读您的问题,我看到您的要求是允许用户加载,在树中编辑,并保存 XML 。这比加载更复杂。以下是步骤:
首先,添加用于加载和保存XML的自定义路由UI命令:
public static class CustomCommands
{
public static readonly RoutedUICommand LoadXMLCommand = new RoutedUICommand("Load XML", "LoadXML", typeof(Window1));
public static readonly RoutedUICommand SaveXMLCommand = new RoutedUICommand("Save XML", "SaveXML", typeof(Window1));
}
接下来,在Window1
类中添加实际的c#逻辑以执行以下操作:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void ExecutedLoadXML(object sender, ExecutedRoutedEventArgs e)
{
string xml = @"<plan xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:noNamespaceSchemaLocation=""schema.xsd"">
<nagłówek>
<autorzy>
<nazwa>Autorzy:</nazwa>
<autor atr=""one"">
<numer>222</numer>
<imię>Rust</imię>
<nazwisko>Snow</nazwisko>
</autor>
<autor>
<numer>111</numer>
<imię>Ian</imię>
<nazwisko>Nower</nazwisko>
</autor>
</autorzy>
</nagłówek>
</plan>
";
var plan = XmlSerializationHelper.LoadFromXML<plan>(xml);
var children = new List<plan>();
children.Add(plan);
treeView1.ItemsSource = null;
treeView1.Items.Clear();
treeView1.ItemsSource = children;
}
private void ExecutedSaveXML(object sender, ExecutedRoutedEventArgs e)
{
var planList = treeView1.ItemsSource as IList<plan>;
if (planList != null && planList.Count > 0)
{
// Kludge to force pending edits to update
treeView1.Focus();
// Replace with actual save code!
Debug.WriteLine(planList[0].GetXml());
}
}
}
正如您所看到的,我只是从硬编码字符串加载,并通过执行调试写入来保存。您将需要用真实逻辑替换它们。
接下来,在XAML中,将上面定义的命令添加到<Window.CommandBindings>
然后,在XAML中添加ToolBarTray
和ToolBar
按钮以加载和保存XML,并将按钮绑定到您添加到上面CommandBindings
的命令。
最后,在XAML中,对于包含数据字段的每个DataTemplate
或HierarchicalDataTemplate
,将该字段的TextBlock
替换为适当的框架元素进行编辑。根据需要添加任何标签作为附加TextBlock
,并将它们全部包装在容器中,例如Grid
。
这是有用的:
<Window x:Class="WpfTreeViewNew.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:w="clr-namespace:WpfTreeViewNew"
Title="Window1" Height="300" Width="600">
<Window.CommandBindings>
<CommandBinding Command="w:CustomCommands.LoadXMLCommand" Executed="ExecutedLoadXML"/>
<CommandBinding Command="w:CustomCommands.SaveXMLCommand" Executed="ExecutedSaveXML"/>
</Window.CommandBindings>
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type w:plan}" ItemsSource="{Binding Path=Items}">
<TextBlock Text="Plan">
</TextBlock>
</HierarchicalDataTemplate >
<HierarchicalDataTemplate DataType="{x:Type w:planNagłówek}" ItemsSource="{Binding Path=autorzy}">
<TextBlock Text="Nagłówek">
</TextBlock>
</HierarchicalDataTemplate >
<HierarchicalDataTemplate DataType="{x:Type w:planNagłówekAutorzy}" ItemsSource="{Binding Path=autor}">
<Grid Margin="3" MinWidth="300">
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="nazwa:" Grid.Column="0" Grid.Row="0"/>
<TextBox Text="{Binding Path=nazwa, Mode=TwoWay}" Grid.Column="1" Grid.Row="0"/>
</Grid>
</HierarchicalDataTemplate >
<DataTemplate DataType="{x:Type w:planNagłówekAutorzyAutor}">
<Border BorderBrush="Gray" BorderThickness="1" MinWidth="300">
<Grid Margin="3" >
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="atr:" Grid.Column="0" Grid.Row="0"/>
<TextBox Text="{Binding Path=atr, Mode=TwoWay}" Grid.Column="1" Grid.Row="0"/>
<TextBlock Text="numer:" Grid.Column="0" Grid.Row="1"/>
<TextBox Text="{Binding Path=numer, Mode=TwoWay}" Grid.Column="1" Grid.Row="1"/>
<TextBlock Text="imię:" Grid.Column="0" Grid.Row="2"/>
<TextBox Text="{Binding Path=imię, Mode=TwoWay}" Grid.Column="1" Grid.Row="2"/>
<TextBlock Text="nazwisko:" Grid.Column="0" Grid.Row="3"/>
<TextBox Text="{Binding Path=nazwisko, Mode=TwoWay}" Grid.Column="1" Grid.Row="3"/>
</Grid>
</Border>
</DataTemplate >
</Window.Resources>
<DockPanel>
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<Button Command="w:CustomCommands.LoadXMLCommand" Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"/>
<Button Command="w:CustomCommands.SaveXMLCommand" Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"/>
</ToolBar>
</ToolBarTray>
<Grid DockPanel.Dock="Bottom">
<TreeView Margin="3" Name="treeView1">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</Grid>
</DockPanel>
</Window>
它产生的UI看起来像:
我不是UI设计师,所以你想要玩这个以获得更美丽的东西。
更新2
GetXML()
扩展方法:
public static class XmlSerializationHelper
{
public static string GetXml<T>(T obj, XmlSerializer serializer, bool omitStandardNamespaces)
{
using (var textWriter = new StringWriter())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true; // For cosmetic purposes.
settings.IndentChars = " "; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
{
if (omitStandardNamespaces)
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
serializer.Serialize(xmlWriter, obj, ns);
}
else
{
serializer.Serialize(xmlWriter, obj);
}
}
return textWriter.ToString();
}
}
public static string GetXml<T>(this T obj, bool omitNamespace)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
return GetXml(obj, serializer, omitNamespace);
}
public static string GetXml<T>(this T obj)
{
return GetXml(obj, false);
}
public static T LoadFromXML<T>(this string xmlString)
{
return xmlString.LoadFromXML<T>(new XmlSerializer(typeof(T)));
}
public static T LoadFromXML<T>(this string xmlString, XmlSerializer serial)
{
T returnValue = default(T);
using (StringReader reader = new StringReader(xmlString))
{
object result = serial.Deserialize(reader);
if (result is T)
{
returnValue = (T)result;
}
}
return returnValue;
}
public static T LoadFromFile<T>(string filename)
{
XmlSerializer serial = new XmlSerializer(typeof(T));
try
{
using (var fs = new FileStream(filename, FileMode.Open))
{
object result = serial.Deserialize(fs);
if (result is T)
{
return (T)result;
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
throw;
}
return default(T);
}
}