我正在尝试编写一个解码某些无符号长值的应用。每个值的格式在XML中表示为:
<Project Name="Project1">
<Message Name="a">
<BitField high="31" low="28">
<value>0001</value>
<value>1010</value>
</Bitfield>
<BitField high="27" low="17">
<value>000111101</value>
</BitField>
<BitField high="16" low="0">100h</BitField>
</Message>
</Project>
现在项目值出现在组合框中。当用户在组合框中选择一个值时,必须在列表框中显示消息类型。然后,当用户在列表框中选择消息类型时,必须显示它们可以容纳的位域和值。现在,当用户为每个位域选择一个值时,最终的双字值必须显示在文本框中。
我遇到了解析完整xml但与选择无关的示例。需要你的帮助。
还有一件事是用户可以在文本框中输入双字值。现在,我如何在文本框中对dword进行解码的反向绑定,并使用上面解释的UI显示相应的消息+值?
更新:现在我已经完成了显示项目值的组合框和显示消息的列表框之间的绑定。接下来我要做的是,当用户在列表框中选择一条消息时,位域必须显示为具有“高”,“低”,“值/ @名称”(此处未显示)的行,然后是value(绑定到值/ @ name)作为列。值/ @名称必须显示为组合框。我敢肯定我可以在dataGrid中这样做,但我使用.net 3.5所以在这里寻找替代方案。此值的文本块也必须是可编辑的,而不是&lt;值&gt; xml中不存在节点。最后,我将“value”列中的条目打包到DWORD。我可以在没有数据网格的情况下在XAML中执行此操作吗?什么是.Net 3.5的数据网格的替代品?
答案 0 :(得分:2)
这里有两个不同的问题 - XML解析问题和转换问题。
要使绑定生效,您需要将XML解析为表示其值的类。对于转换问题,我向您指出TypeConverters的概念,它使用相当简单。对于XML解析问题,我想强调LINQ-to-XML,我认为这是蜜蜂的膝盖。它的几行甚至可以重构XML源中最复杂的对象图。对于Project / Message / BitField的示例,我已经部分实现了一个可以为您提供模式的解决方案。
请注意“LoadFromXml”方法。这使用填充对象图的linq-to-xml表达式。此查询在XML源中更改的一件事是它期望集合节点(即或)被集合节点包围(即)
public class Project
{
public string Name { get; set; }
public List<Message> MessageCollection = new List<Message>();
public void LoadFromXml(string xmlString)
{
// From System.Xml.Linq
XDocument xDocument = XDocument.Parse(xmlString);
// The following assumes your XML is well formed, is not missing attributes and has no type conversion problems. In
// other words, there is (almost) zero error checking.
if (xDocument.Document != null)
{
XElement projectElement = xDocument.Element("Project");
if (projectElement != null)
{
Name = projectElement.Attribute("Name") == null ? "Untitled Project" : projectElement.Attribute("Name").Value;
MessageCollection = new List<Message>
(from message in xDocument.Element("Project").Elements("Messages")
select new Message()
{
Name = message.Attribute("Name").Value,
BitfieldCollection = new List<BitField>
(from bitField in message.Elements("Bitfields")
select new BitField() {High = int.Parse(bitField.Attribute("High").Value), Low = int.Parse(bitField.Attribute("Low").Value)})
}
);
}
}
}
}
public class Message
{
public string Name { get; set; }
public List<BitField> BitfieldCollection = new List<BitField>();
}
public class BitField
{
public int High { get; set; }
public int Low { get; set; }
public List<string> ValueCollection = new List<string>();
}
答案 1 :(得分:1)
您肯定需要牢记模型和视图的分离以及模型的外部表示。根据您的实际XML有多大以及那种API让您觉得舒适,您可以使用几种完全不同的方式来读取XML并将其转换为实际对象,然后将其用作UI的模型。牢记这种分离是非常重要的。
我将假设您的XML是来自其他一些处理的实际数据 - 这意味着将会有很多项目标记,具有大量Message标记,并且位域跨度与消息不同。如果这个假设是错误的,并且对于整个应用程序或一个大文件中的所有消息都修复了位域跨度,那么您可以节省一些时间和空间。
因此,假设一切都是可变的,从标签中获取值的最快方法就是创建XPathDocumen并通过XPath选择,您可以将其保存为字符串或甚至在配置中。例如,这将为您提供所有Value标签(现在称为节点)
//Project/Message/BitField/Value
并且由于节点的对象具有父指针,您可以收集共享父(到列表或数组)的所有值,然后为父(BitField)创建一个对象,保留它并确保它具有父指针XmlNode的。一旦你拥有了所有的BitField对象,你就可以进行类似的扫描,然后分组进入他们的父母(Message)并再次获得Project-s。这只是一种方式,你可以使用更短的XPath来开始从BitField收集并自己抓住他们的孩子。
您还可以创建一些普通类来逐字表示XML标记(每个字段一个数据成员,每个标记一个类),然后为XmlSerialization设置属性。这需要一些试验来使名称恰到好处,但是你可以通过函数调用“反序列化”整个文件并从.NET接收数组或数组:-)。
如果您的文件非常非常大,那么您可能必须使用XmlTextReader并从上到下扫描文件 - 与XPath选择完全相反(XmlTextReader是最轻的解析方式,不会创建大量的额外的对象,但你必须在几个外观迭代它,并始终从父对象“走”,因为它是单向的。
UI方面,如果你有时间进行实验,可能值得尝试构建一个包含3个组合框和一个文本字段的边界框,然后列出这些 - 这样你就有了更多的灵活性,即你不要不得不遵循网格的力学。
哦,如果你对XML格式有任何影响,试着让ppl始终将该值放入值标记,即使它只是一个。 XML文件会更长一点,但您的处理将会简化。
答案 2 :(得分:1)
这可以使用数据绑定和XMLReaders完成。首先创建你的UI,最好是在父面板内(这样我们可以设置面板的datacontext,子控件都将继承这个上下文)。
接下来创建一个自定义类(让我们称之为Project)。确保此类中的每个字段都更新PropertyDependencyInfo,否则数据绑定将不起作用。
然后将UI控件的Content或Itemssource属性绑定到Project类的字段。
然后,使用XMLReader类或XPathReader类创建用于读取XML的代码。然后,当您从文件中访问数据时,请设置新Project对象的字段以匹配您要读取的数据。
实例化Project对象并正确分配XML的值后,将父Panel从UI的DataContext属性设置为Project对象。然后应更新所有UI字段。
如果您需要加载其他文件,您只需重复使用不同文件名的XML读取。
至于您的更新:可以使用以下任一方式管理行和列:
Grid / UniformGrid控件,其RowDefinition和ColumnDefinition子项在运行时创建和修改,以便管理增加和减少的字段数
或:一组StackPanel,每列一个(因为列数永远不会改变)。您可以直接将Comboboxes添加到StackPanel以获取value / @ name列,或者您可以修改StackPanel的ItemsTemplate(如果它有一个,我目前无法到达机器进行检查)。
这个问题应该分成几个子问题,因为它涵盖了一系列主题,如果有针对这些问题专门定制的问题,你更有可能得到问题每个方面的详细答案。 / p>