我有一个ObservableCollection
个对象,这些对象被分类为一个名称和一组3D坐标。我还有一个ObservableCollection
层,每层都应该有一个2D网格。
目标是使用ItemsControl
(可能是嵌套的)以下列方式显示这些对象:如果Z坐标确定图层,并且X和Y坐标指定每个对象在网格上的位置,则该对象应显示在TabControl
中,其中TabItem
对应于Z坐标,并托管Grid
,其中Grid.Row
和Grid.Column
属性确定对象的名称写在TabItem
。
重要提示:虽然每个3D坐标只使用一次,但一个“Entry”对象可能有多个3D坐标,因此可能会在网格和/或不同的TabItems
上出现不同的时间。
注意:数据模型不是刻在石头上;如果问题可以通过其他数据模型解决,我愿意改变它。然而,显示器是客户要求 - 它可能会被修改,但我需要非常好的论据。
对象看起来像这样(BindableBase
来自Prism Library):
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
相关联。
有没有人有进一步的想法去探索?正如我所说,如果能够提供更简单的解决方案,我也可以重新构建我的数据模型。
我已经探索了使用Button
而不是TabControl
的路径,即将数据绑定到点击状态以在网格上显示不同的信息。然而,这只是改变了问题并创建了一个新问题:数据不再预先加载,这对客户的要求至关重要。
我现在正在考虑建议改变对客户的要求,并完全设计出不同的数据模型。为了避免再次走错路线,我非常感谢社区中有人对这个问题有强烈意见,他们愿意与我分享。
答案 0 :(得分:0)
在获得同行专家提供的一些非常有价值的离线建议后,我决定反对客户建议的数据模型,并为他们提供替代解决方案。现在的方法是以自上而下的方式填充 View 。
实质上,这意味着之前我的 Z 坐标现在是定义<%= stylesheet_link_tag ....
<%= javascript_include_tag ....
s的专用EntryLayer
对象的索引。每个TabItem
都有一个EntryLayer
,指的是那些ObservableCollection<Entry>
部分的Entry
。
这与初始模型形成对比,因为现在不再可能EntryLayer
可以有多个坐标;相反,Entry
本身可能会以不同的坐标多次存在。
我是如何将其出售给客户的?我告诉他们,现在Entry
可能有自定义选项,可能在相同或其他Entry
的表示之间有所不同,例如,通过使用用户指定的颜色和字体,同时仍然指向相同的基础信息。它为我提供了更多的实现工作,但它通过将其置于新功能的形状中优雅地解决了僵局。