【问题标题】:ItemsControl to display several layers of dataItemsControl 显示几层数据
【发布时间】:2018-01-04 09:23:43
【问题描述】:

我有一个ObservableCollection 对象,这些对象使用名称和一组 3D 坐标进行分类。我还有一个ObservableCollection 层,每个层都应该包含一个 2D 网格。

问题设置

目标是使用ItemsControl,可能是嵌套的,以下列方式显示这些对象:如果 Z 坐标确定图层,并且 X 和 Y 坐标指定每个对象在网格上的位置,那么对象应显示在TabControl 中,其中TabItem 对应于Z 坐标并承载Grid,其中Grid.RowGrid.Column 属性确定对象名称在TabItem 上的写入位置。

重要提示:虽然每个 3D 坐标仅使用一次,但一个“条目”对象可能有多个 3D 坐标,因此可能会在网格上出现不同时间和/或不同的TabItems

注意:数据模型不是一成不变的;如果问题可以用另一个数据模型解决,我愿意改变它。然而,显示是客户的要求——它可能会被修改,但我需要非常好的论据。

背景资料

对象看起来像这样(BindableBase 来自 Prism 库):

public class Entry : BindableBase {
  public string Name { set; get; }

  private EntryCoordinates coordinates;
  public EntryCoordinates Coordinates {
    set { SetProperty(ref coordinates, value); }
    get { return coordinates; }
  }
}

public class EntryCoordinates : BindableBase {
  private int x;
  public int X {
    set { SetProperty(ref x, value); }
    get { return x; }
  }

  private int y;
  public int Y {
    set { SetProperty(ref y, value); }
    get { return y; }
  }

  private int z;
  public int Z {
    set { SetProperty(ref z, value); }
    get { return z; }
  }
}

Entry 对象托管在“入口层”中:

public class EntryLayer : ObservableCollection<Entry> {
}

最终,我希望能够通过 UI 修改 Entry 对象(实际上更复杂),因此双向数据绑定是绝对必要的。

到目前为止的努力

使用@Rachel 出色的WPF Grid Extension,我实现了一个ItemsControl,它根据需要填充了Grid

<ItemsControl ItemsSource="{Binding EntryLayers, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <Grid GridExtension.RowCount="{Binding RowCount}"
            GridExtension.ColumnCount="{Binding ColumnCount}"
            GridExtension.StarRows="{Binding StarRows}"
            GridExtension.StarColumns="{Binding StarColumns}"
            IsItemsHost="True"/>
    </ItemsPanelTemplate>

  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemContainerStyle>
    <Style>
      <Setter Property="Grid.Row" Value="{Binding Coordinates.X}"/>
      <Setter Property="Grid.Column" Value="{Binding Coordinates.Y}"/>
    </Style>
  </ItemsControl.ItemContainerStyle>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <GridCellThumb XCoordinate="{Binding Coordinates.X}"
                     YCoordinate="{Binding Coordinates.Y}">
        <Thumb.Template>
          <ControlTemplate>
            <TileControl Entry="{Binding}"/>
          </ControlTemplate>
        </Thumb.Template>
      </GridCellThumb>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

GridCellThumb 是一个自定义控件,允许拖放(为清楚起见,此处省略)并公开坐标依赖属性:

public class GridCellThumb : Thumb {
  public static readonly DependencyProperty XCoordinateProperty = DependencyProperty.Register("XCoordinate", typeof(int), typeof(GridCellThumb));
  public int XCoordinate {
    get { return (int)GetValue(XCoordinateProperty); }
    set { SetValue(XCoordinateProperty, value); }
  }

  public static readonly DependencyProperty YCoordinateProperty = DependencyProperty.Register("YCoordinate", typeof(int), typeof(GridCellThumb));
  public int YCoordinate {
    get { return (int)GetValue(YCoordinateProperty); }
    set { SetValue(YCoordinateProperty, value); }
  }
}

TileControl 是一个显示Entry 名称的用户控件:

<StackPanel Orientation="Vertical">
  <Label Content="{Binding Path=Name}" />
</StackPanel>

我一直在寻找如何将原始 ItemsControl 包装在 TabControl 模板中,以便正确显示条目的目标,可能在不同时间。例如,绑定到Coordinates.Z 路径有效,但会创建与条目一样多的TabItems

<TabControl ItemsSource="{Binding Entries}">
  <TabControl.ItemContainerStyle>
    <Style TargetType="TabItem">
      <Setter Property="Header"
              Value="{Binding Coordinates.Z}" />
      <Setter Property="TabIndex"
              Value="{Binding Coordinates.Z}" />
    </Style>
  </TabControl.ItemContainerStyle>
  <!-- the ItemsControl goes here -->
</TabControl>

我已经尝试过@greg40 (nested ItemsControl)、@d.moncada (another nested ItemsControl) 和@Sheridan (going up the visual tree) 提出的解决方案,但在将Entry 与给定的EntryLayer

有没有人有进一步的想法要探索?正如我所说,我也愿意重新构建我的数据模型,如果这会导致更简单的解决方案。

2018-01-08 更新

我已经探索了使用Buttons 而不是TabControl 的路径,将它们的点击状态数据绑定到在网格上显示不同的信息。然而,这只是转移了问题并产生了一个新问题:不再预加载数据,这对客户的要求至关重要。

我现在正在强烈考虑向客户提出改变要求的建议,并设计一个完全不同的数据模型。为了避免再次走错路,如果社区中有人对这个问题有强烈的意见并愿意与我分享,我将不胜感激。

【问题讨论】:

  • 另一个想法:EntryCoordinate 之间存在一对多的关系。 Coordinate 确定图层和网格。将ItemsControl 作为外部标签并将TabControl 作为内部标签是否更可行?但是如何渲染TabItems 以便它们包含相应的Grids?

标签: c# wpf xaml mvvm


【解决方案1】:

在同行专家提出了一些非常有价值的离线建议后,我决定反对客户建议的数据模型,并为他们提供替代解决方案。现在的方法是以自上而下的方式填充 View

本质上,这意味着以前我的Z 坐标现在是定义TabItems 的专用EntryLayer 对象的索引。每个EntryLayer 都有一个ObservableCollection&lt;Entry&gt;,它指代那些Entrys,它是EntryLayer 的一部分。

这与初始模型形成对比,因为现在Entry 不可能有多个坐标;相反,Entry 本身可能以不同的坐标多次存在。

我是如何把它卖给客户的?我告诉他们,现在Entry 可以具有自定义选项,这些选项可能在相同或其他EntryLayers 上的表示之间有所不同,例如,通过使用用户指定的颜色和字体,同时仍指向相同的基本信息。它给了我更多的工作来完成实现,但它通过将其置于新功能的形式中优雅地解决了死锁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-11
    • 2012-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多