自定义DependencyProperty问题

时间:2010-09-25 23:01:59

标签: wpf wpf-controls binding

我在WPF userControls上对自定义依赖项属性进行了测试,但是没有用...请帮忙。

任务:

拥有UserControl - MyCircle,构建CenterXCenterY可绑定属性。

这是我的代码:

MyTestCircle.xaml

<Canvas x:Name="mainCanvas" Width="100" Height="100">
    <Ellipse x:Name="myCircle" Fill="Red" 
             Width="{Binding ElementName=mainCanvas, Path=ActualWidth}"
             Height="{Binding ElementName=mainCanvas, Path=ActualHeight}"/>     
</Canvas>

MyTestCircle.xaml.cs

public partial class MyTestCircle : UserControl
{
    public MyTestCircle()
    {
        InitializeComponent();
    }

    public double CenterX
    {
        get { return (double)GetValue(CenterXProperty); }
        set { SetValue(CenterXProperty, value); }
    }

    public static readonly DependencyProperty CenterXProperty =
        DependencyProperty.Register("CenterX", typeof(double), typeof(MyTestCircle),
        new UIPropertyMetadata(double.NaN, 
            new PropertyChangedCallback(OnCenterYChanged), 
            new CoerceValueCallback(OnCenterXCoerceValue)));

    public static void OnCenterXChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        MyTestCircle circle = (MyTestCircle)obj;
        Canvas.SetLeft(circle, (double)args.NewValue - circle.Width / 2);
    }

    public static object OnCenterXCoerceValue(DependencyObject source, object obj)
    {
        MyTestCircle circle = (MyTestCircle)obj;
        return Canvas.GetLeft(circle) + circle.Width / 2;            
    }




    public double CenterY
    {
        get { return (double)GetValue(CenterYProperty); }
        set { SetValue(CenterYProperty, value); }
    }

    public static readonly DependencyProperty CenterYProperty =
        DependencyProperty.Register("CenterY", typeof(double), typeof(MyTestCircle),
        new UIPropertyMetadata(double.NaN,
            new PropertyChangedCallback(OnCenterYChanged),
            new CoerceValueCallback(OnCenterYCoerceValue)));

    public static void OnCenterYChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        MyTestCircle circle = (MyTestCircle)obj;
        Canvas.SetTop(circle, (double)args.NewValue - circle.Height / 2);
    }

    public static object OnCenterYCoerceValue(DependencyObject source, object obj)
    {
        MyTestCircle circle = (MyTestCircle)obj;
        return Canvas.GetTop(circle) + circle.Height / 2;
    }

}

测试画布:

<Canvas x:Name="mainCanvas">
    <my:MyTestCircle Canvas.Left="104" Canvas.Top="132" x:Name="myTestCircle1" />
    <Line Stroke="Black"
        X1="0" Y1="0" 
        X2="{Binding ElementName=myTestCircle1, Path=CenterX}"
        Y2="{Binding ElementName=myTestCircle1, Path=CenterY}"
        />
</Canvas>

因此,测试画布中的Line不会跟随圆圈的中心...为什么?

编辑:

注:
在代码或设计器中,我永远不会隐藏 CenterXCenterY属性。我需要将这些属性与Left / Top画布属性“链接”......这可能吗?

2 个答案:

答案 0 :(得分:1)

您实际上从未设置过CenterX和CenterY,因此它们保持默认状态,但还有其他问题。问题似乎是homeworkey所以我只是指出问题。

如果您想在设置值之前调整值,则使用

Coerce handlers,例如限制价值。在这种情况下,他们不需要加上你错误地施放obj,这是MyTestCircle的双倍。

您的更改处理程序正在使用尚未设置的MyTestCircle UserControl的宽度和高度,您应该设置它们或访问已设置的大小值。您可以在用户控件中使用Ellipse并设置UserControl的大小。当X发生变化时,你也会有一个错字调用Y处理程序。

如果这是家庭作业,试着解决上面提到的问题,我们可以再看看。如果没有,你只想要一条线到中心我会删除属性完全使用内置的Left,Top属性并添加一个转换-50,-50的RenderTransform。

您需要额外的属性吗?如果设置Left和Top,他们是否需要更新?如果是这样custom Attached Properties将是一个很好的解决方案。

答案 1 :(得分:0)

你需要这样的结果吗?

exmpale

public Circle()
    {
        InitializeComponent();


    }
    public double CenterX
    {
        get { return (double)GetValue(CenterXProperty); }
        set { SetValue(CenterXProperty, value); }
    }

    public static readonly DependencyProperty CenterXProperty =
        DependencyProperty.Register("CenterX", typeof(double), typeof(Circle),
        new UIPropertyMetadata(double.NaN,
            new PropertyChangedCallback(OnCenterXChanged),
            new CoerceValueCallback(OnCenterXCoerceValue)));


    public static void OnCenterXChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        Circle circle = (Circle)obj;
        Canvas.SetLeft(circle, (double)args.NewValue - circle.Width / 2);
    }

    public static object OnCenterXCoerceValue(DependencyObject source, object obj)
    {
        return double.Parse(obj.ToString());
    }




    public double CenterY
    {
        get { return (double)GetValue(CenterYProperty); }
        set { SetValue(CenterYProperty, value); }
    }

    public static readonly DependencyProperty CenterYProperty =
        DependencyProperty.Register("CenterY", typeof(double), typeof(Circle),
        new UIPropertyMetadata(double.NaN,
            new PropertyChangedCallback(OnCenterYChanged),
            new CoerceValueCallback(OnCenterYCoerceValue)));

    public static void OnCenterYChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        Circle circle = (Circle)obj;
        Canvas.SetTop(circle, (double)args.NewValue - circle.ActualHeight / 2);
    }

    public static object OnCenterYCoerceValue(DependencyObject source, object obj)
    {
          return double.Parse(obj.ToString());
    }

<Canvas x:Name="mainCanvas" Width="100" Height="100">
        <Ellipse x:Name="myCircle" Fill="Red" 
             Width="{Binding ElementName=mainCanvas, Path=Width}"
             Height="{Binding ElementName=mainCanvas, Path=Height}"/>
    </Canvas>

用于在MainWindows中测试创建^

private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            myTestCircle1.CenterY = 200;
            myTestCircle1.CenterX = 300;

        }

编辑:

private void Window_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Left)
    {

        myTestCircle1.CenterX -= 1.0;
    }
    else if (e.Key == Key.Right)
    {

        myTestCircle1.CenterX += 1.0;
    }
}

绑定是有效的......或者你还需要别的什么?