Создание редактора WPF для файла XML на основе схемы - PullRequest
10 голосов
/ 17 декабря 2009

Вот сценарий. Мы используем большой файл конфигурации XML для одного из наших серверных продуктов. Этот файл довольно хорошо выложен и проверен на соответствие XSD-файлу.

Теперь пришло время создать графический интерфейс настройки для поддержки этого файла, и я хотел бы погрузиться в WPF, чтобы сделать это. Я мог бы выложить отдельную форму для каждого раздела конфигурации, рефакторинг и перераспределение каждый раз, когда мы добавляем параметр в файл конфигурации, но я надеюсь, что есть более умный способ сделать это.

Так как у меня уже есть строго типизированная комбинация xml / xsd, я надеюсь, что есть элегантный метод для создания пользовательского интерфейса, чтобы достаточно легко редактировать это. Я знаю, что мог бы написать преобразование xml-> xaml, но надеялся, что уже есть что-то, что может сделать для меня тяжелую работу?

Заранее спасибо ..

Ответы [ 4 ]

12 голосов
/ 18 декабря 2009

Как бы я это сделал:

Я бы начал с создания простого класса модели представления, который охватывает 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 свойство SchemaInfo, вместо предоставления имени базового элемента.

Очевидно, я бы хотел добавить проверку, поэтому я бы добавил метод проверки, который проверял бы свойство XmlElement SchemaInfo и интерпретировал его. (Предполагая, что элементы, которые вы проверяете, являются простым содержимым, это не должно быть сложно.) Существует миллион учебных пособий о том, как реализовать проверку в приложениях WPF, поэтому я не буду вдаваться в подробности.

Если есть тонны опций конфигурации, и у вас есть какой-то разумный способ сгруппировать их по категориям, я бы построил класс более высокого уровня, который предоставил бы (как минимум) два свойства - свойство CategoryName строки и OptionsViews collection - заполните его из XML-документа и добавьте в окно ResourceDictionary. В окне я бы привязал его к TabControl, например ::1010 *

<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 раньше, это довольно хороший проект для начала. Это познакомит вас с основами привязки данных, контроля и проверки элементов, а конечный результат будет чем-то полезным и, вероятно, выглядит довольно хорошо.

И вы заметите, что хотя разметка, используемая при создании шаблонов, довольно многословна, существует только два шаблона. Единственный код в приложении (пока) - это код, который предоставляет XmlElement s для пользовательского интерфейса.

4 голосов
/ 05 сентября 2011

Вот, пожалуйста, мы создали один для вашего требования. Этот инструмент полностью создан с учетом WPF.

http://wpfxmleditor.codeplex.com/

1 голос
/ 12 сентября 2014

Не WPF, но очень познавательно - Динамически сгенерированный редактор XML-данных от Марка Клифтона

Статья с исходным кодом для Windows формирует информацию о создании графического интерфейса для редактирования XML на основе XSD.

Долго искали что-то подобное.

0 голосов
/ 25 октября 2015

Для представления простых конфигов xml (если пользовательские редакторы значений не требуются) можно напрямую связать XElement с представлением, используя HierarchicalDataTemplate.

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);
    }
}

Есть несколько хороших примеров преобразования обратного bool в visibility.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...