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

发布于 2024-09-16 10:18:03 字数 680 浏览 4 评论 0原文

我有一个对象集合,我想将它们表示为 Grid,每个对象表示为 矩形(或 Button - 避风港)尚未确定这一点)。每个对象都有一个 XY 属性,表示其在 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 将表示为网格左上角的矩形。对象two将位于对象one右侧的槽中,将位于one下方,并且< code>four 将位于右下角的插槽中。

我试图弄清楚如何以惯用的 WPF 方式创建这两个模板(例如使用 DataTemplate 和类似的构造),但需要一些帮助。有什么建议吗?

我还希望能够将模板存储在主窗口之外的单独文件中,但我也不知道如何做到这一点。

I have a collection of objects that I would like to represent as a Grid with each object represented as a Rectangle (or a Button - haven't settled on this yet). Each object has an X and a Y property which represent its location in the Grid.

For example, I might have four objects:

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}

The Grid should have two rows and two columns. Object one would be represented as a Rectangle in the top left part of the Grid. Object two would be in the slot to the right of object one, three would be below one, and four would be in the bottom right slot.

I am trying to figure out how to create both templates in an idiomatic WPF manner (e.g. using DataTemplate and similar constructs), but need some help. Any advice?

I'd also like to be able to store the template(s) in a separate file from my main window, but am not sure how to do that either.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

独闯女儿国 2024-09-23 10:18:03

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

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

根据您的设计,您可以将网格定位与对象的实际视觉呈现分开,以便您可以在其他地方重用该呈现。这可能就是我的处理方式。为我的对象创建 UserControl 后,我会在 Grid.Resources 中创建一个 DataTemplate (因为它描述了特定的 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 文件来包含仅属于窗口的资源,这有点痛苦。

As to your first question, this is probably the pattern you're looking for:

<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>

In a real application, you'd set the ItemsControl.ItemsSource to a Binding whose source is a collection of objects, and then create a DataTemplate like:

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

As far as organizing the code into separate files goes: you should consider creating a UserControl for displaying the object, instead of a DataTemplate. It's no more difficult to create one than the other, and UserControls are classes that live in their own XAML files and can be instantiated in XAML, like any other object, by their name.

Depending on your design, you might separate out the grid positioning from the actual visual presentation of the object, so that you can reuse the presentation elsewhere. That's probably how I'd approach it. After creating a UserControl for my object, I'd create a DataTemplate in Grid.Resources (since it's describing how that specific Grid should display the objects) like this:

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

It's also possible to organize XAML using an include-like approach: create a standalone XAML file that contains a resource dictionary, and then merge the dictionaries into your window's (or application's, or anything else really) resource dictionary:

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

This can be a good approach for organizing a lot of styles and templates, though a problem with it is that if ResourceDictionary.MergedDictionaries is set, you can't put any items directly in the dictionary, so you have to create a separate XAML file to contain the resources that belong solely to the window, which is kind of a pain.

街角卖回忆 2024-09-23 10:18:03

一种方法是使用 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。

One approach would be to use a ListView. You can set it's ItemsPanel to be a Canvas and then in the datatemplate bind the Canvas.Top and Canvas.Left to the X and Y co-ordinates that you want the item to have:

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

If you need to you can use a converter to multiply the YPosition and XPosition by the cell size so that the properties can refer to the cell number rather than the pixel size.


On the other (simpler) hand: If you know in advance how many rows or columns the grid will have and there is one, and only one, element per cell then you may be able to use a UniformGrid instead of a ListView.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文