使用Converter的TemplateBinding有什么问题?

7
我正在创建一个游戏桌。我希望将场地大小(一个场地是一个正方形)指定为一个附加属性,并使用这些数据设置ViewPort的值,该ViewPort会绘制2x2矩阵(而平铺模式将完成其余游戏桌的工作)。
我很困惑,因为绑定不起作用。
在XAML中测试行为所需的行:
<DrawingBrush Viewport="0,0,100,100" ViewportUnits="Absolute" TileMode="None">

游戏桌基于DrawingPaint的示例:http://msdn.microsoft.com/en-us/library/aa970904.aspx(这里有一张图片)。
XAML:
<Window x:Class="Sokoban.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Sokoban"
    Title="Window1" Height="559" Width="419">
    <Window.Resources>
        <local:FieldSizeToRectConverter x:Key="fieldSizeConverter" />
        <Style x:Key="GameDesk" TargetType="{x:Type Rectangle}">
            <Setter Property="local:GameDeskProperties.FieldSize" Value="50" />
            <Setter Property="Fill">
                <Setter.Value>
                    <!--<DrawingBrush Viewport="0,0,100,100" ViewportUnits="Absolute" TileMode="None">-->
                    <DrawingBrush Viewport="{TemplateBinding local:GameDeskProperties.FieldSize, Converter={StaticResource fieldSizeConverter}}" ViewportUnits="Absolute" TileMode="None">
                        <DrawingBrush.Drawing>
                            <DrawingGroup>
                                <GeometryDrawing Brush="CornflowerBlue">
                                    <GeometryDrawing.Geometry>
                                        <RectangleGeometry Rect="0,0,100,100" />
                                    </GeometryDrawing.Geometry>
                                </GeometryDrawing>

                                <GeometryDrawing Brush="Azure">
                                    <GeometryDrawing.Geometry>
                                        <GeometryGroup>
                                            <RectangleGeometry Rect="0,0,50,50" />
                                            <RectangleGeometry Rect="50,50,50,50" />
                                        </GeometryGroup>
                                    </GeometryDrawing.Geometry>
                                </GeometryDrawing>
                            </DrawingGroup>
                        </DrawingBrush.Drawing>
                    </DrawingBrush>
               </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <StackPanel>
        <Rectangle Style="{StaticResource GameDesk}" Width="300" Height="150" />        
    </StackPanel>
</Window>

转换器和属性定义:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Diagnostics;
using System.Windows.Data;

namespace Sokoban
{
    public class GameDeskProperties : Panel
    {

        public static readonly DependencyProperty FieldSizeProperty;

        static GameDeskProperties()
        {
            PropertyChangedCallback fieldSizeChanged =
                new PropertyChangedCallback(OnFieldSizeChanged);
            PropertyMetadata fieldSizeMetadata =
                new PropertyMetadata(50, fieldSizeChanged);

            FieldSizeProperty = DependencyProperty.RegisterAttached("FieldSize",
                typeof(int), typeof(GameDeskProperties), fieldSizeMetadata);
        }

        public static int GetFieldSize(DependencyObject target)
        {
            return (int)target.GetValue(FieldSizeProperty);
        }

        public static void SetFieldSize(DependencyObject target, int value)
        {
            target.SetValue(FieldSizeProperty, value);
        }


        static void OnFieldSizeChanged(DependencyObject target,
                              DependencyPropertyChangedEventArgs e)
        {
            Debug.WriteLine("FieldSize just changed: " + e.NewValue);
        }
    }

    [ValueConversion(/* sourceType */ typeof(int), /* targetType */ typeof(Rect))]
    public class FieldSizeToRectConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Debug.Assert(targetType == typeof(int));

            int fieldSize = int.Parse(value.ToString());
            return new Rect(0, 0, 2 * fieldSize, 2 * fieldSize);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            // should not be called in our example
            throw new NotImplementedException();
        }
    }
}
1个回答

11

TemplateBindings 只适用于在模板中定义的依赖属性(在 ControlTemplate 中)。你只需要将其更改为具有 AncestorTypeRelativeSourceBinding (此外,附加属性需要在绑定中使用括号):

...
<DrawingBrush Viewport="{Binding Path=(local:GameDeskProperties.FieldSize), Converter={StaticResource fieldSizeConverter}, RelativeSource={RelativeSource AncestorType={x:Type Rectangle}}}"
...

编辑 更新了 RelativeSource 绑定,因为它未在 ControlTemplate 内定义。


我在Visual Studio的输出窗口中发现了以下错误:System.Windows.Data Error: 2 : 找不到目标元素的主要FrameworkElement或FrameworkContentElement。BindingExpression:Path=(0); DataItem=null; 目标元素为'DrawingBrush' (HashCode=35191196); 目标属性为'Viewport' (类型'Rect')。 - MartyIX
抱歉,我没有仔细看您设置的属性。我已经更新了答案,现在它应该可以正常工作了。 - Abe Heidebrecht
谢谢,我已经从你之前的例子中找到了答案。 - MartyIX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接