【问题标题】:Creating a WPF editor for XML file based on schema基于架构为 XML 文件创建 WPF 编辑器
【发布时间】:2010-12-27 17:08:08
【问题描述】:

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

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

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

提前谢谢..

【问题讨论】:

    标签: c# wpf xml xaml xsd


    【解决方案1】:

    我会怎么做:

    我将首先构建一个简单的视图模型类,该类包含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; }
       }
    }
    

    现在我可以从XmlDocument 填充ElementView 对象的集合,将该集合添加到窗口的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}"/>
    

    (注意:后面你可以花点心思,比如根据底层XmlElement的数据类型来定义OptionView的子类。然后你可以为每个子类定义DataTemplates,如只要每个使用SharedSizeGroup 在双列网格中显示项目,第二列就可以包含日期选择器、单选按钮或任何适合子类的内容,并且它们都会在运行时整齐地布局.)

    一旦我完成了这项工作,这不会花很长时间,我就会开始扩展 OptionView 类。例如,如果您的架构正在为 xs:annotation 元素中的元素存储人类可读的标签(如果不是,为什么不呢?),我会让 Name 属性将其从 @ 中提取出来987654335@ 的SchemaInfo 属性,而不是暴露底层元素名称。

    显然我想添加验证,所以我想添加一个验证方法来检查XmlElementSchemaInfo 属性并对其进行解释。 (假设您要验证的元素是简单的内容,这应该不难。)关于如何在 WPF 应用程序中实现验证的教程有上百万个,所以我不会在这里详细介绍。

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

    <TabControl ItemsSource="{DynamicResource OptionCategories}">
       <TabControl.ItemContainerStyle>
          <Style TargetType="{x:Type CategoryView}">
             <Setter Property="Header" Value="{Binding Path=CategoryName}"/>
             <Setter Property="Content" Value="{Binding Path=OptionsViews}"/>
             <Setter Property="ContentTemplate" Value="{StaticResource OptionViewTemplate}"/>
          </Style>
       </TabControl.ItemContainerStyle>
    </TabControl>
    

    或者到某个项目控件,其项目容器模板创建了一个Expander。或者其他的东西。 (保证所有代码都未经测试!不过,其中大部分是从工作项目中复制出来的。)

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

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

    【讨论】:

      【解决方案2】:

      给你,我们为你的要求创建了一个。这个工具完全是在牢记 WPF 的基础上创建的。

      http://wpfxmleditor.codeplex.com/

      【讨论】:

      • 你打算为你的编辑发布一个版本吗?它目前只是源代码,没有迹象表明代码的状态(即,它大部分是完整的吗?alpha、beta、稳定?)
      • 很抱歉回复晚了,我没有任何发布计划,你可以下载并构建它。
      【解决方案3】:

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

      一篇关于创建用于编辑基于 XSD 的 XML 的 GUI 的 Windows 窗体源代码的文章。

      一直在寻找类似的东西。

      【讨论】:

        【解决方案4】:

        要呈现简单的 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.

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-26
          • 1970-01-01
          • 2011-03-05
          • 1970-01-01
          • 2010-10-29
          相关资源
          最近更新 更多