WPF: Trouble databinding to custom Dependency Property

M

moondaddy

I have a windows WPF sample project which is starting to work pretty good.
I can drag shapes and lines, and connect a straight line to any place on a
custom rectangle shape's boarder. Now I have a custom Polyline object which
I had to create some DPs to use in a MultiBinding. However, since I'm not
strong in using custom DPs yet, I'm getting an error when binding to the
custom DP.

When you run this project:

1) Drag the right end of the Red line (this is the Line) to the rectangle
and drop it. now drag the rectangle. You can see it stays connected.

2) Now drag the right end of the Blue line (this is the Polyline) and drop
it on the rectangle. You will get the error.

3) Note, you can right click on the ends of the Polyline to add additional
line segments. its pretty cool.

Can someone please show me how to create and bind thes custom DPs?

Thanks.

Note: the attachment was 107K so I could not post it. please send me an
email go g e o r g e p At n w i s Dot n e t.
and I will email it to you.
 
W

Walter Wang [MSFT]

Hi moondaddy,

To simply the scenario, I will use your previous version of code (v3) to
demonstrate the idea on how to bind a Polyline's last point to a
Rectangle's border.

First, we can create following static class to add two DPs to the Polyline
and handle the callback when the value gets changed (i.e. the data binding
returns updated data):

public static class PolylineDPs
{
public static readonly DependencyProperty EndPointXProperty =
DependencyProperty.Register("EndPointX", typeof(double), typeof(Polyline),
new FrameworkPropertyMetadata(new
PropertyChangedCallback(EndPointX_Changed)));
public static readonly DependencyProperty EndPointYProperty =
DependencyProperty.Register("EndPointY", typeof(double), typeof(Polyline),
new FrameworkPropertyMetadata(new
PropertyChangedCallback(EndPointY_Changed)));

private static void EndPointX_Changed(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
Polyline pl = (Polyline)sender;
Point p = pl.Points[pl.Points.Count - 1];
p.X = (double) (e.NewValue);
pl.Points[pl.Points.Count - 1] = p;
}

private static void EndPointY_Changed(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
Polyline pl = (Polyline)sender;
Point p = pl.Points[pl.Points.Count - 1];
p.Y = (double)(e.NewValue);
pl.Points[pl.Points.Count - 1] = p;
}
}



After that, you can freely use the same LineBindingConverter and
MultiBinding object to bind the Polyline's end point to the Rectangle's
border:

Polyline DrawPolyline()
{
Polyline pl = new Polyline();
pl.Stroke = Brushes.Blue;
pl.StrokeThickness = 3;
pl.Points.Add(new Point(10, 10));
pl.Points.Add(new Point(50, 10));
pl.Points.Add(new Point(150, 150));
dragCanvas.Children.Add(pl);
return pl;
}

Line myLine = DrawLine();
SimpleRectangle myRect = DrawRectangle();
Polyline pl = DrawPolyline();

MultiBinding multiBinding = new MultiBinding();
multiBinding.Converter = new LineBindingConverter();
multiBinding.ConverterParameter = 1.0;

Binding binding = new Binding();
binding.Source = myRect;
binding.Path = new PropertyPath("Left");
multiBinding.Bindings.Add(binding);

binding = new Binding();
binding.Source = myRect;
binding.Path = new PropertyPath("Width");
multiBinding.Bindings.Add(binding);

myLine.SetBinding(Line.X2Property, multiBinding);
pl.SetBinding(PolylineDPs.EndPointXProperty, multiBinding);

multiBinding = new MultiBinding();
multiBinding.Converter = new LineBindingConverter();
multiBinding.ConverterParameter = 0.3;

binding = new Binding();
binding.Source = myRect;
binding.Path = new PropertyPath("Top");
multiBinding.Bindings.Add(binding);

binding = new Binding();
binding.Source = myRect;
binding.Path = new PropertyPath("Height");
multiBinding.Bindings.Add(binding);

myLine.SetBinding(Line.Y2Property, multiBinding);
pl.SetBinding(PolylineDPs.EndPointYProperty, multiBinding);


This will both bind the Line's end point and the Polyline's end point to
the same point on the right border of the Rectangle.

Hope this helps.

Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
M

moondaddy

Thanks Walter! As always, your samples and explanations are extremely
helpful. This is starting to work quite nicely.

Now, I need to know how to remove these bindings.

For example, here's my steps:

1) I drag the end of the polyline over the rectangle and on the
dragcompleted even I execute the code from the previous post which binds the
end of the polyline to the rectangle. Good.
2) Now I drag the end of the line off and away from the rectangle so I need
to Un-Bind the line from the rectangle.
3) Then, when I drag the rectangle, the 'EndPointY_Changed' event fires and
the end of the polyline jumps back to where its connected to the rectangle.

private static void EndPointY_Changed(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
Polyline pl = (Polyline)sender;
Point p = pl.Points[pl.Points.Count - 1];
p.Y = (double)(e.NewValue);
pl.Points[pl.Points.Count - 1] = p;
}
}


I tried making the variables private at the class level so I could set them
to null after dragging the line away from the rectangle:

MultiBinding multiBinding;
Binding binding;

but that had no effect.

How do you recommend Un-Binding the line from the rectangle?

Thanks.



Walter Wang said:
Hi moondaddy,

To simply the scenario, I will use your previous version of code (v3) to
demonstrate the idea on how to bind a Polyline's last point to a
Rectangle's border.

First, we can create following static class to add two DPs to the Polyline
and handle the callback when the value gets changed (i.e. the data binding
returns updated data):

public static class PolylineDPs
{
public static readonly DependencyProperty EndPointXProperty =
DependencyProperty.Register("EndPointX", typeof(double), typeof(Polyline),
new FrameworkPropertyMetadata(new
PropertyChangedCallback(EndPointX_Changed)));
public static readonly DependencyProperty EndPointYProperty =
DependencyProperty.Register("EndPointY", typeof(double), typeof(Polyline),
new FrameworkPropertyMetadata(new
PropertyChangedCallback(EndPointY_Changed)));

private static void EndPointX_Changed(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
Polyline pl = (Polyline)sender;
Point p = pl.Points[pl.Points.Count - 1];
p.X = (double) (e.NewValue);
pl.Points[pl.Points.Count - 1] = p;
}

private static void EndPointY_Changed(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
Polyline pl = (Polyline)sender;
Point p = pl.Points[pl.Points.Count - 1];
p.Y = (double)(e.NewValue);
pl.Points[pl.Points.Count - 1] = p;
}
}



After that, you can freely use the same LineBindingConverter and
MultiBinding object to bind the Polyline's end point to the Rectangle's
border:

Polyline DrawPolyline()
{
Polyline pl = new Polyline();
pl.Stroke = Brushes.Blue;
pl.StrokeThickness = 3;
pl.Points.Add(new Point(10, 10));
pl.Points.Add(new Point(50, 10));
pl.Points.Add(new Point(150, 150));
dragCanvas.Children.Add(pl);
return pl;
}

Line myLine = DrawLine();
SimpleRectangle myRect = DrawRectangle();
Polyline pl = DrawPolyline();

MultiBinding multiBinding = new MultiBinding();
multiBinding.Converter = new LineBindingConverter();
multiBinding.ConverterParameter = 1.0;

Binding binding = new Binding();
binding.Source = myRect;
binding.Path = new PropertyPath("Left");
multiBinding.Bindings.Add(binding);

binding = new Binding();
binding.Source = myRect;
binding.Path = new PropertyPath("Width");
multiBinding.Bindings.Add(binding);

myLine.SetBinding(Line.X2Property, multiBinding);
pl.SetBinding(PolylineDPs.EndPointXProperty, multiBinding);

multiBinding = new MultiBinding();
multiBinding.Converter = new LineBindingConverter();
multiBinding.ConverterParameter = 0.3;

binding = new Binding();
binding.Source = myRect;
binding.Path = new PropertyPath("Top");
multiBinding.Bindings.Add(binding);

binding = new Binding();
binding.Source = myRect;
binding.Path = new PropertyPath("Height");
multiBinding.Bindings.Add(binding);

myLine.SetBinding(Line.Y2Property, multiBinding);
pl.SetBinding(PolylineDPs.EndPointYProperty, multiBinding);


This will both bind the Line's end point and the Polyline's end point to
the same point on the right border of the Rectangle.

Hope this helps.

Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no
rights.
 
W

Walter Wang [MSFT]

You could use BindingOperations.ClearAllBindings() or ClearBinding to clear
the binding(s):

#BindingOperations.ClearAllBindings Method (System.Windows.Data)
http://msdn2.microsoft.com/en-gb/library/system.windows.data.bindingoperatio
ns.clearallbindings.aspx

Please note: Clearing the binding removes the binding so that the value of
the dependency property is changed to whatever it would have been without
the binding. This value could be a default value, an inherited value, or a
value from a data template binding.


Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top