Настройка отображения данных с привязкой данных и WPF - Использование нескольких элементов управления для отображения данных XML

ОГЛАВЛЕНИЕ

Использование нескольких элементов управления для отображения данных XML

Весьма распространенным способом работы с иерархическими данными является отображение каждого уровня иерархии отдельным элементом управления. Для примера предположим, что у нас есть система, представляющая клиентов, заказы и сведенья о заказах. В такой ситуации поле со списком может использоваться для отображения клиентов, список для отображения всех заказов выбранных клиентов и, наконец, ItemsControl для отображения сведений о выбранном заказе. Это отличный способ отображения иерархических данных, и реализовать его в WPF довольно легко.

На Рис. 4, основанном на описанной выше ситуации, показан упрощенный пример данных, с которыми может работать приложение, обернутых в компонент XmlDataProvider платформы WPF. Эти данные согут отображаться в интерфейсе пользователя, подобном показанному наРис. 5. Обратите внимание, что клиентов и заказы можно выбирать, но сведения о заказе существуют в форме списка только для чтения. Этому есть причина – возможность выбирать визуальный объект следует предоставлять только тогда, когда он воздействует на состояние приложения или является изменяемым.

Рис. 4. Иерархия клиентов заказов и сведений о заказах в формате XML

<XmlDataProvider x:Key="xmlData">
  <x:XData>
   <customers >
    <customer name="Customer 1">
     <order desc="Big Order">
      <orderDetail product="Glue" quantity="21" />
      <orderDetail product="Fudge" quantity="32" />
      </order>
      <order desc="Little Order">
       <orderDetail product="Ham" quantity="1" />
       <orderDetail product="Yarn" quantity="2" />
      </order>
     </customer>
     <customer name="Customer 2">
      <order desc="First Order">
       <orderDetail product="Mousetrap" quantity="4" />
      </order>
     </customer>
    </customers>
   </x:XData>
</XmlDataProvider>

 

Рис. 5 Один из способов отображения данных XML

В коде XAML наРис. 6 описано, как использовать эти различные элементы управления для отображения только что показанных иерархических данных. Это окно не требует кода; оно существует полностью в коде XAML.

Рис. 6. Код XAML для привязки иерархических данных XML к интерфейсу пользователя

<Grid DataContext=
   "{Binding Source={StaticResource xmlData},
   XPath=customers/customer}"
   Margin="4" 
  >
  <Grid.RowDefinitions>
   <RowDefinition Height="Auto" />
   <RowDefinition />
   <RowDefinition />
  </Grid.RowDefinitions>

  <!-- CUSTOMERS -->
  <DockPanel Grid.Row="0">
   <TextBlock DockPanel.Dock="Top" FontWeight="Bold" Text="Customers" />
   <ComboBox
    IsSynchronizedWithCurrentItem="True"
    ItemsSource="{Binding}"
    >
    <ComboBox.ItemTemplate>
     <DataTemplate>
      <TextBlock Text="{Binding XPath=@name}" />
     </DataTemplate>
    </ComboBox.ItemTemplate>
   </ComboBox>
  </DockPanel>

  <!-- ORDERS -->
  <DockPanel Grid.Row="1">
   <TextBlock DockPanel.Dock="Top" FontWeight="Bold" Text="Orders" />
   <ListBox
    x:Name="orderSelector" 
    DataContext="{Binding Path=CurrentItem}"
    IsSynchronizedWithCurrentItem="True" 
    ItemsSource="{Binding XPath=order}"
    >
    <ListBox.ItemTemplate>
     <DataTemplate>
      <TextBlock Text="{Binding XPath=@desc}" />
     </DataTemplate>
    </ListBox.ItemTemplate>
   </ListBox>
  </DockPanel>

  <!-- ORDER DETAILS -->
  <DockPanel Grid.Row="2">
   <TextBlock DockPanel.Dock="Top" FontWeight="Bold" 
    Text="Order Details" />
   <ItemsControl 
    DataContext=
     "{Binding ElementName=orderSelector, Path=SelectedItem}"
    ItemsSource="{Binding XPath=orderDetail}">
    <ItemsControl.ItemTemplate>
     <DataTemplate>
      <TextBlock>
       <Run>Product:</Run>
       <TextBlock Text="{Binding XPath=@product}" />
       <Run>(</Run>
       <TextBlock Text="{Binding XPath=@quantity}" />
       <Run>)</Run>
      </TextBlock>
     </DataTemplate>
    </ItemsControl.ItemTemplate>
   </ItemsControl>
  </DockPanel>
</Grid>

Обратите внимание на широкое использование коротких запросов XPath для указания платформе WPF на место, где нужно получить привязанные значения. Класс Binding предоставляет свойство XPath, которому можно выделить любой запрос XPath, поддерживаемый методом XmlNode.SelectNodes. Внутренние механизмы WPF используют этот метод для исполнения запросов XPath. Увы, это значит, что поскольку XmlNode.SelectNodes не поддерживает на данный момент использование функций XPath, их не поддерживает и привязка данных WPF.

Поле со списком клиентов и список заказов производят привязку к получающемуся набору узлов запроса XPath, выполняемого запросом DataContext корневого элемента Grid (таблица). DataContext списка автоматически возвратит CurrentItem представления коллекции, являющегося оберткой для коллекции XmlNodes, создаваемой для DataContext таблицы. Другими словами, DataContext списка – это выбранный в настоящий момент клиент. Поскольку ItemsSource списка неявно привязан к собственному DataContext (потому что не было указано другого источника) и его привязка ItemsSource исполняет запрос XPath для получения элементов <order> из DataContext, то ItemsSource фактически привязан к списку заказов выбранного клиента.

Помните, что при привязке к данным XML реально привязка происходит к объектам, созданным вызовом к XmlNode.SelectNodes. При неосторожности можно получить несколько элементов управления, выполняющих привязку к логически эквивалентным, но физически различным наборам XmlNodes. Это обусловлено тем, что при каждом вызове к XmlNode.SelectNodes создается новый набор узлов XmlNode, даже если каждый раз передавать тот же запрос XPath тому же узлу XmlNode. Это особая проблема привязки к данным XML, так что при привязке к бизнес-объектам ее можно спокойно игнорировать.