Как отобразить коллекцию элементов с шаблоном, который использует Grid в WPF? - PullRequest
1 голос
/ 27 августа 2010

У меня есть коллекция объектов, которые я хотел бы представить как Grid с каждым объектом, представленным как Rectangle (или Button - еще не определились с этим).Каждый объект имеет свойства X и Y, которые представляют его местоположение в Grid.

Например, у меня может быть четыре объекта:

var one = new MyClass(){X=0, Y=0}
var two = new MyClass(){X=1, Y=0}
var three = new MyClass(){X=0, Y=1}
var four = new MyClass(){X=1, Y=1}

Grid должно иметь две строки и два столбца.Объект one будет представлен как Rectangle в верхней левой части сетки.Объект two будет в слоте справа от объекта one, three будет ниже one, а four будет в правом нижнем слоте.

Я пытаюсьвыяснить, как создавать оба шаблона в идиоматической манере WPF (например, используя DataTemplate и подобные конструкции), но нужна некоторая помощь.Любой совет?

Я также хотел бы иметь возможность хранить шаблон (ы) в отдельном файле из моего основного окна, но я не уверен, как это сделать.

Ответы [ 2 ]

2 голосов
/ 27 августа 2010

Что касается вашего первого вопроса, это, вероятно, шаблон, который вы ищете:

<ItemsControl>
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="100"/>
          <ColumnDefinition Width="100"/>
          <ColumnDefinition Width="100"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="50"/>          
          <RowDefinition Height="50"/>          
          <RowDefinition Height="50"/>          
        </Grid.RowDefinitions>
      </Grid>
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <Button Grid.Row="1" Grid.Column="2">R1C2</Button>
  <Button Grid.Row="2" Grid.Column="1">R2C1</Button>
  <Button Grid.Row="0" Grid.Column="0">R0C0</Button>
</ItemsControl>

В реальном приложении вы должны установить ItemsControl.ItemsSource на Binding, источник которогоколлекцию объектов, а затем создайте DataTemplate, например:

<DataTemplate DataType="{x:Type MyObject}">
   <Rectangle Grid.Row="{Binding Row}" Grid.Column="{Binding Column}">
     <!-- other visuals go here -->
   </Rectangle>
</DataTemplate>

Что касается организации кода в отдельных файлах: вам следует рассмотреть возможность создания UserControl для отображения объекта вместоDataTemplate.Создать один не сложнее, чем другой, и UserControl - это классы, которые живут в своих собственных файлах XAML и могут быть созданы в XAML, как и любой другой объект, по имени.

В зависимости от вашегодизайн, вы можете отделить расположение сетки от фактического визуального представления объекта, чтобы вы могли использовать презентацию в другом месте.Наверное, так я и подхожу.После создания UserControl для моего объекта я бы создал DataTemplate в Grid.Resources (поскольку он описывает, как этот конкретный Grid должен отображать объекты), например:

<DataTemplate DataType="{x:Type MyObject}">
   <DockPanel Grid.Row="{Binding Row}" Grid.Column="{Binding Column}">
      <local:MyObjectUserControl DataContext="{Binding}"/>
   </DockPanel>
</DataTemplate>

Этотакже возможно организовать XAML с использованием подхода, подобного включенному: создать автономный файл XAML, содержащий словарь ресурсов, а затем объединить словари в словарь ресурсов вашего окна (или приложения, или чего-либо еще):

<Window.Resources>
  <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
      <ResourceDictionary Source="myresourcedictionary.xaml"/>
      <ResourceDictionary Source="myresourcedictionary2.xaml"/>
    </ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>
</Window.Resources>

Это может быть хорошим подходом для организации большого количества стилей и шаблонов, хотя проблема в том, что если установлено ResourceDictionary.MergedDictionaries, вы не можете помещать какие-либо элементы непосредственно в словарь, поэтому вам нужно создать отдельныйXAML-файл, содержащий ресурсы, которые принадлежат только окну, что является своего рода болью.

1 голос
/ 27 августа 2010

Один из подходов заключается в использовании ListView. Вы можете установить для нее ItemsPanel как Canvas, а затем в табличке данных привязать Canvas.Top и Canvas.Left к координатам X и Y, которые вы хотите, чтобы элемент имел:

<ListView>
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas/>
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
    <ListView.ItemTemplate>
        <DataTemplate>
             <Button Canvas.Top="{Binding YPosition}", Canvas.Left="{Binding XPosition}"/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Если вам нужно, вы можете использовать конвертер для умножения YPosition и XPosition на размер ячейки, чтобы свойства могли ссылаться на номер ячейки, а не на размер пикселя.


С другой (более простой) стороны: если вы заранее знаете, сколько строк или столбцов будет иметь сетка, и имеется один и только один элемент на ячейку, то вы можете использовать UniformGrid вместо ListView.

...