Reputation: 28586
I did a test on custom dependency properties on WPF userControls, and does not work... Please help.
Having an UserControl - MyCircle, build the CenterX
and CenterY
bindable properties.
Here is my code:
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;
}
}
Testing Canvas:
<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>
So, the Line in the Testing canvas does not follow the center of the circle... Why?
Remark:
In the code or Designer, I could never chanage the CenterX
and CenterY
properties. I need that that properties be "linked" with the Left/Top canvas properties... Is that possible?
Upvotes: 0
Views: 484
Reputation: 7170
You are never actually setting CenterX and CenterY so they remain at their default but there are other issues. The question seems homeworkey so I'll just point out the problems.
Coerce handlers are used when you want to adjust a value before setting it e.g. limiting a value. In this situation they're not needed plus you incorrectly cast obj which is a double to a MyTestCircle.
Your change handlers are using the Width and Height of the MyTestCircle UserControl which haven't been set, you should either set them or access size values that have been set. You could just have an Ellipse in the user control and set the size of the UserControl. You also have a typo calling the Y handler when X changes.
If this is Homework try to fix the problems mentioned and we can have another look. If not and you just want a line to the Center I would remove the properties completely use the built-in Left,Top properties and add a RenderTransform that translates -50,-50.
Do you need the extra properties? Do they need to update if you set Left and Top? If so custom Attached Properties would be a nice solution.
Upvotes: 1
Reputation: 15378
You need such a result?
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>
for testing create in 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;
}
}
binding is work...or you need something else?
Upvotes: 0