数据模板中的WPF绑定不能用于定制类
使用显示可用平铺背景列表的ComboBox工作。这只是一个简单的ComboBox,其中一个ItemSource被设置为MapTileBackground对象的集合。数据模板中的WPF绑定不能用于定制类
的MapTileBackground类与属性完全定义:
public partial class MapTileBackground
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public byte[] Content { get; set; }
public Nullable<int> Color { get; set; }
public int StrokeColor { get; set; }
public byte StrokeThickness { get; set; }
}
其在一个单独的库中定义和我宁愿不改变它。
我已经定义了一个简单的形状的扩展绘制背景::
public class MapTileBackgroundPreview : Shape
{
public static readonly DependencyProperty SizeProperty = DependencyProperty.Register("Size", typeof(Point), typeof(MapTileBackgroundPreview));
public static readonly DependencyProperty TileBackgroundProperty = DependencyProperty.Register("TileBackground", typeof(MapTileBackground), typeof(MapTileBackgroundPreview));
public MapTileBackgroundPreview()
{
layout = new Hex.Layout(Hex.Orientation.Flat, new Hex.Point(8, 8), new Hex.Point(4, 4));
Size = new Point(8, 8);
TileBackground = null;
}
private Hex.Layout layout;
protected override Geometry DefiningGeometry
{
get
{
var points = layout.HexCorners(0, 0).ToArray();
var path = new PathFigure();
path.StartPoint = points[5].ToWin();
for (var i = 0; i < 6; i++)
path.Segments.Add(new LineSegment(points[i].ToWin(), true));
var geo = new PathGeometry();
geo.Figures.Add(path);
return geo;
}
}
public Point Size
{
get
{
return (Point)GetValue(SizeProperty);
}
set
{
SetValue(SizeProperty, value);
layout.Size = value.ToHex();
layout.Origin = new Hex.Point(layout.Size.X/2, layout.Size.Y/2);
}
}
public MapTileBackground TileBackground
{
get
{
return (MapTileBackground)GetValue(TileBackgroundProperty);
}
set
{
SetValue(TileBackgroundProperty, value);
if (value == null)
{
Fill = Brushes.Transparent;
Stroke = Brushes.Black;
StrokeThickness = 1;
}
else
{
Stroke = value.Stroke();
StrokeThickness = value.StrokeThickness();
Fill = value.Fill(layout.Orientation);
}
}
}
}
布局只是屏幕像素坐标和六方晶系之间的转换工具。定义几何只需添加6行的六角线。 TileBackground设置器在给定非空MapTileBackground时,会根据背景定义更新描边和填充。我已经成功测试了这个控件(在组合框数据模板之外)。
和说:
<DataTemplate x:Key="TileListItemRenderer">
<Grid Width="225">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="24"/>
<ColumnDefinition Width="75"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<local:MapTileBackgroundPreview Grid.Row="0" Grid.Column="0" Size="12,12" VerticalAlignment="Center" HorizontalAlignment="Center" TileBackground="{Binding /}"/>
<Label Grid.Row="0" Grid.Column="1" Content="{Binding Name}" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold"/>
<TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding Description}" HorizontalAlignment="Stretch" VerticalAlignment="Top" TextWrapping="Wrap" />
</Grid>
</DataTemplate>
所以我只是创建一个形状,和两个标签,形状绑定到当前MapTileBackground对象(组合框的ItemSource是MapTileBackground对象的集合),以及标签名称和说明。
我的问题是形状始终绘制为空(因为在TileBackground为null),并且从不调用setter。名称标签和描述文本块的行为与预期相同(显示正确的文本)。在我的调试尝试期间,我在预览对象上创建了一个id属性,然后调用TileBackground Setter并将其绑定到Id属性(避免当前的对象绑定),同样,TileBackgroundId setter从不被调用。我甚至添加了一个绑定到Id的新标签,看看它是否正常工作,并按预期显示了该标识。这些变化再次无效。打开下拉菜单时从不设置TileBackgroundId或TileBackground属性。
<DataTemplate x:Key="TileListItemRenderer">
<Grid Width="225">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="24"/>
<ColumnDefinition Width="75"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<local:MapTileBackgroundPreview Grid.Row="0" Grid.Column="0" Size="12,12" VerticalAlignment="Center" HorizontalAlignment="Center" TileBackgroundId="{Binding Id}"/>
<Label Grid.Row="0" Grid.Column="0" Content="{Binding Id}" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold"/>
<Label Grid.Row="0" Grid.Column="1" Content="{Binding Name}" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold"/>
<TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding Description}" HorizontalAlignment="Stretch" VerticalAlignment="Top" TextWrapping="Wrap" />
</Grid>
</DataTemplate>
public static readonly DependencyProperty TileBackgroundIdProperty = DependencyProperty.Register("TileBackgroundId", typeof(int), typeof(MapTileBackgroundPreview));
public int TileBackgroundId
{
get
{
return (int)GetValue(TileBackgroundIdProperty);
}
set
{
SetValue(TileBackgroundIdProperty, value);
TileBackground = TMapTileBackgroundTool.Get(value);
}
}
TMapTileBackgroundTool.Get()返回基于标识正确的对象。
我还测试了数据模板外部的MapTileBackgroundPreview设置TileBackgroundId的实例。
有什么想法是怎么回事?
的CLR包装的依赖setter方法是不应该被设定为WPF绑定引擎调用GetValue
和SetValue
方法直接:
Setters not run on Dependency Properties?
Why are .NET property wrappers bypassed at runtime when setting dependency properties in XAML?
的getter和CLR wrapper属性的setter应该分别为和分别调用GetValue
和SetValue
方法。
如果您想在依赖属性设置做一些事情,你应该注册一个回调:
public static readonly DependencyProperty TileBackgroundIdProperty = DependencyProperty.Register("TileBackgroundId", typeof(int), typeof(MapTileBackgroundPreview),
new PropertyMetadata(0, new PropertyChangedCallback(TileBackgroundIdChanged)));
public int TileBackgroundId
{
get
{
return (int)GetValue(TileBackgroundIdProperty);
}
set
{
SetValue(TileBackgroundIdProperty, value);
}
}
private static void TileBackgroundIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MapTileBackgroundPreview ctrl = (MapTileBackgroundPreview)d;
ctrl.TileBackground = TMapTileBackgroundTool.Get((int)e.NewValue);
}
我不能相信我在搜索答案或研究数据绑定时没有遇到过,因此完全是我的错。感谢快速回答。无论如何,我使用更改事件重新实现了所有三个属性,并将Id绑定到TileBackgroundId时一切正常。当绑定\到TileBackground时,我仍然没有收到任何东西。我可以用基于int的属性居住,我只是想知道为什么它不能以第二种方式工作。谢谢。 – David
可以共享'Hex'?或者在上面的代码中删除它? – Iron
在这种情况下,Hex是一个名称空间别名。 – David