代码之家  ›  专栏  ›  技术社区  ›  Pat

如何使用WPF中使用网格的模板显示项目集合?

  •  1
  • Pat  · 技术社区  · 14 年前

    我有一个对象集合,我想表示为 Grid 将每个对象表示为 Rectangle (或 Button -还没定下来)。每个对象都有一个 X 以及 Y 表示其在 网格 .

    例如,我可能有四个对象:

    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}
    

    这个 网格 应该有两行两列。对象 one 将被表示为 矩形 在网格的左上角。对象 two 会在物体右边的槽里 , three 会在下面 ,和 four 会在右下角的位置。

    我试图找出如何以惯用的WPF方式创建这两个模板(例如使用 DataTemplate 但需要一些帮助。有什么建议吗?

    我也希望能够将模板存储在主窗口的单独文件中,但也不确定如何这样做。

    2 回复  |  直到 14 年前
        1
  •  2
  •   Robert Rossney    14 年前

    关于你的第一个问题,这可能是你正在寻找的模式:

    <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 用于显示对象,而不是 数据模板 . 创造一个并不比另一个困难,而且 用户控件 s是存在于它们自己的XAML文件中的类,可以像任何其他对象一样,通过它们的名称在XAML中实例化。

    根据您的设计,您可以将网格定位与对象的实际可视表示分离,以便可以在其他地方重用该表示。我可能就是这么想的。在创建 用户控件 对于我的对象,我将创建一个 数据模板 在里面 Grid.Resources (因为它描述了 Grid 应该显示对象)如下所示:

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

    还可以使用类似include的方法组织XAML:创建一个包含资源字典的独立XAML文件,然后将字典合并到窗口的(或应用程序的)资源字典中:

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

    这是一种组织许多样式和模板的好方法,尽管它的一个问题是如果 ResourceDictionary.MergedDictionaries 如果设置为,则不能将任何项直接放入字典中,因此必须创建单独的XAML文件以包含仅属于窗口的资源,这有点麻烦。

        2
  •  1
  •   Martin Harris    14 年前

    一种方法是使用ListView。您可以将其ItemsPanel设置为画布,然后在datatemplate中绑定画布。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 而不是列表视图。