基于模式为XML文件创建WPF编辑器

时间:2009-12-17 15:40:47

标签: c# wpf xml xaml xsd

这是场景。我们为我们的某个服务器产品使用大型XML配置文件。此文件布局合理,并根据XSD文件进行验证。

现在是时候构建用于维护此文件的配置GUI了,我想深入研究WPF来实现它。我可以为每个配置部分布置一个单独的表单,每次我们在配置文件中添加一个选项时重构和重新分发,但我希望有更聪明的方法来做到这一点。

由于我已经有一个强类型的xml / xsd组合,我希望有一种优雅的方法来构建一个UI来轻松编辑它。我知道我可以编写一个xml-> xaml转换,但希望有一些东西可以帮我完成繁重的工作吗?

提前致谢..

4 个答案:

答案 0 :(得分:12)

我是怎么做到的:

我首先构建一个包含XmlElement的简单视图模型类,并将其作为配置选项公开。这个类可能非常简单,例如:

public class OptionView
{
   private XmlElement XmlElement;
   public OptionView(XmlElement xmlElement)
   {
      XmlElement = xmlElement;
   }
   public string Name { get { return XmlElement.Name; } }
   public string Value 
   { 
      get { return XmlElement.InnerText; } 
      set { XmlElement.InnerText = value; }
   }
}

现在我可以从ElementView填充XmlDocument个对象的集合,将该集合添加到窗口的ResourceDictionary,并使用简单的DataTemplate格式化对象,例如:

<DataTemplate x:Key="OptionViewTemplate" DataType={x:Type local:OptionView}>
   <Grid>
       <Grid.ColumnDefinitions>
          <ColumnDefinition SharedSizeGroup="Name"/>
          <ColumnDefinition SharedSizeGroup="Value"/>
       </Grid.ColumnDefinitions>
       <Label Content="{Binding Name}" Grid.Column="0"/>
       <TextBox Text="{Binding Value}" Grid.Column="1"/>
   </Grid>
</DataTemplate>
...
<ItemsControl Grid.IsSharedSizeScope="True"
    ItemsSource="{DynamicResource OptionCollection}"/>

(注意:稍后,您可以获得幻想,并根据例如基础OptionView的数据类型定义XmlElement的子类。然后您可以定义DataTemplate s对于每个子类,只要每个子类使用SharedSizeGroup在两列网格中呈现项目,第二列就可以包含日期选择器,或单选按钮,或者适合子类的任何内容,并且它'所有这些都在运行时得到了整齐的布局。)

一旦我开始工作,这不会花费很长时间,我会开始扩展OptionView课程。例如,如果你的模式为xs:annotation元素中的元素存储了一个人类可读的标签(如果不存在,为什么不呢?),我会将Name属性提取为超出XmlElement的{​​{1}}属性,而不是公开底层元素名称。

显然我想添加验证,所以我添加了一个验证方法来检查SchemaInfo的{​​{1}}属性并解释它。 (假设您正在验证的元素是简单的内容,那应该不会很难。)有一百万篇关于如何在WPF应用程序中实现验证的教程,所以我不会在这里详细介绍。

如果有大量的配置选项并且您有一些智能的方法将它们分组到类别中,我将构建一个更高级别的类,它暴露(至少)两个属性 - 字符串XmlElement属性和{ {1}}集合 - 从XML文档中填充它,并将其添加到窗口SchemaInfo。在窗口中,我将它绑定到CategoryName,例如:

OptionsViews

或者某个项目容器模板创建ResourceDictionary的项目控件。或者其他的东西。 (所有代码都保证未经测试!但大多数代码都是从工作项目中复制出来的。)

如果您以前没有对WPF做过任何事情,这是一个非常好的项目。它将向您展示数据绑定和项目控制和验证的基础知识,最终结果将是有用的,可能看起来很不错。

您会注意到,虽然创建模板所涉及的标记非常详细,但只有两个模板。应用程序中唯一的代码(到目前为止)是将TabControl公开给UI的代码。

答案 1 :(得分:4)

在这里,我们根据您的要求创建了一个。这个工具完全是通过记住WPF而创建的。

http://wpfxmleditor.codeplex.com/

答案 2 :(得分:1)

不是WPF,但非常有启发性 - A Dynamically Generated XML Data Editor by Marc Clifton

一篇包含windows表单源代码的文章,内容涉及创建用于基于XSD编辑XML的GUI。

一直在寻找类似的东西。

答案 3 :(得分:0)

要呈现简单的xml配置(如果不需要值的自定义编辑器),可以使用HierarchicalDataTemplate直接将XElement绑定到视图。

XAML:

<TreeView Grid.IsSharedSizeScope="True" 
          ItemsSource="{Binding Xml.Elements}">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Elements}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition SharedSizeGroup="Name"/>
                    <ColumnDefinition SharedSizeGroup="Value"/>
                </Grid.ColumnDefinitions>
                <Label Content="{Binding Name}" />
                <!--Show TextBox only for leaf elements-->
                <TextBox Grid.Column="1"
                         Text="{Binding Value}" 
                         Visibility="{Binding HasElements,
                            Converter={StaticResource reverseBoolToVisibilityConverter}}"/>
            </Grid>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

查看模型:

class ConfigViewModel:INotifyPropertyChanged
{
    public XElement Xml { get; private set;}

    //example of persistence infrastructure
    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    public void Load(string fileName)
    {
        Xml = XElement.Load(fileName);
        PropertyChanged(this, new PropertyChangedEventArgs("Xml"));
    }
    public void Save(string fileName)
    {
        Xml.Save(fileName);
    }
}

There are some good examples for reversed bool to visibility converter.