Пользовательская проблема DependencyProperty - PullRequest
0 голосов
/ 26 сентября 2010

Я провел тест пользовательских свойств зависимостей для пользовательских элементов управления WPF и не работает ... Пожалуйста, помогите.

Задача:

Используя UserControl - MyCircle, создайте привязываемые свойства CenterX и CenterY.

Вот мой код:

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>

Итак, линия на холсте тестирования не следует за центром круга ... Почему?

EDIT:

Примечание:
В коде или конструкторе я никогда не смог изменить свойства CenterX и CenterY. Мне нужно, чтобы эти свойства были "связаны" со свойствами левого / верхнего холста ... Это возможно?

Ответы [ 2 ]

1 голос
/ 26 сентября 2010

Вы никогда не устанавливаете CenterX и CenterY, поэтому они остаются по умолчанию, но есть другие проблемы. Вопрос кажется доморощенным, поэтому я просто укажу на проблемы.

Обработчики Coerce используются, когда вы хотите отрегулировать значение до его установки, например. ограничение значения. В этой ситуации они не нужны, плюс вы неверно разыгрываете объект obj, который является двойным к MyTestCircle.

Ваши обработчики изменений используют ширину и высоту MyTestCircle UserControl, которые не были установлены, вы должны либо установить их, либо получить доступ к установленным значениям размера. Вы могли бы просто иметь Ellipse в пользовательском элементе управления и установить размер UserControl. У вас также есть опечатка, вызывающая обработчик Y при изменении X.

Если это домашняя работа, постарайтесь исправить упомянутые проблемы, и мы можем взглянуть по-другому. Если нет, и вы просто хотите линию к центру, я бы полностью удалил свойства, используя встроенные свойства Left, Top, и добавил бы RenderTransform, который переводит -50, -50.

Вам нужны дополнительные свойства? Нужно ли обновлять, если вы установили Left и Top? Если так, то пользовательские Прикрепленные свойства было бы хорошим решением.

0 голосов
/ 26 сентября 2010

Вам нужен такой результат?

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;

        }

EDIT:

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;
    }
}

привязка это работа ... или вам нужно что-то еще?

...