我有一个非常简单的WPF应用程序,它在画布中呈现简单形状:
蓝色方块为ItemsControl
,红色圆圈为Controls
我的应用程序中的以下步骤是在形状之间添加连接线。将移动shaphes,我希望自动移动连接。我想知道如何添加连接绑定。
所有都适用于canvas直接子(容器),但如果我想连接节点,它不起作用。似乎如果我没有明确地致电Canvas.SetLeft()
和Canvas.SetTop()
,那么Canvas.GetLeft()
和Canvas.GetTop()
会返回NAN。
我该怎么办?
Canvas.GetLeft()
所有对象吗?
这是示例的源代码。您可以找到here完整示例:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Container container1 = new Container() { Width = 100, Height = 100 };
Node node1 = new Node() { Width = 50, Height = 50 };
container1.Items.Add(node1);
Container container2 = new Container() { Width = 100, Height = 100 };
Node node2 = new Node() { Width = 50, Height = 50 };
container2.Items.Add(node2);
Canvas.SetLeft(container2, 200);
myCanvas.Children.Add(container1);
myCanvas.Children.Add(container2);
}
}
class Container : ItemsControl
{
protected override void OnRender(DrawingContext drawingContext)
{
drawingContext.DrawRectangle(
Brushes.Blue, null, new Rect(0, 0, this.Width, this.Height));
}
}
class Node : Control
{
protected override void OnRender(DrawingContext drawingContext)
{
drawingContext.DrawEllipse(
Brushes.Red, null,
new Point(Width / 2, Height / 2), Width / 2, Height / 2);
}
}
这是我实现形状之间连接的方式:
public Shape AddConnection(UIElement source, UIElement target)
{
Connector conn = new Connector();
conn.SetBinding(Connector.StartPointProperty,
CreateConnectorBinding(source));
conn.SetBinding(Connector.EndPointProperty,
CreateConnectorBinding(target));
return conn;
}
private MultiBinding CreateConnectorBinding(UIElement connectable)
{
// Create a multibinding collection and assign an appropriate converter to it
MultiBinding multiBinding = new MultiBinding();
multiBinding.Converter = new ConnectorBindingConverter();
// Create binging #1 to IConnectable to handle Left
Binding binding = new Binding();
binding.Source = connectable;
binding.Path = new PropertyPath(Canvas.LeftProperty);
multiBinding.Bindings.Add(binding);
// Create binging #2 to IConnectable to handle Top
binding = new Binding();
binding.Source = connectable;
binding.Path = new PropertyPath(Canvas.TopProperty);
multiBinding.Bindings.Add(binding);
// Create binging #3 to IConnectable to handle ActualWidth
binding = new Binding();
binding.Source = connectable;
binding.Path = new PropertyPath(FrameworkElement.ActualWidthProperty);
multiBinding.Bindings.Add(binding);
// Create binging #4 to IConnectable to handle ActualHeight
binding = new Binding();
binding.Source = connectable;
binding.Path = new PropertyPath(FrameworkElement.ActualHeightProperty);
multiBinding.Bindings.Add(binding);
return multiBinding;
}
Connector
对象非常简单。它有一个LineGeometry并公开两个DependencyProperties来计算起点和终点。
public static readonly DependencyProperty StartPointProperty =
DependencyProperty.Register(
"StartPoint",
typeof(Point),
typeof(Connector),
new FrameworkPropertyMetadata(
new Point(0, 0),
FrameworkPropertyMetadataOptions.AffectsMeasure));
public static readonly DependencyProperty EndPointProperty =
DependencyProperty.Register(
"EndPoint",
typeof(Point),
typeof(Connector),
new FrameworkPropertyMetadata(
new Point(0, 0),
FrameworkPropertyMetadataOptions.AffectsMeasure));
答案 0 :(得分:3)
一切都是错的,如果不解决问题,我就无法回答这个问题。
因为你正在使用绑定来连接东西,而你的“可连接”并没有描述它是一个节点还是一个容器,或两者兼而有之,我会假设它可以同时存在。 例如:
public interface IConnection
{
IConnectable A { get; set; }
IConnectable B { get; set; }
}
public class Connection : IConnection, Line
{
DependencyProperty AProperty = ...;
DependencyProperty BProperty = ...;
}
public class Node : IConnectable
{
DependencyProperty ConnectionProperty = ...;
}
public class Container : IConnectable
{
DependencyProperty ConnectionProperty = ...;
ObservableCollection<IConnectable> Children = ...;
}
public class ContainerView : IConnectable
{
DependencyProperty ConnectionPointProperty = ...;
DependencyProperty ConnectionProperty = ...;
void OnSizeChanged(...)
{
RecalcConnectionPoint();
}
void OnConnectionPointOtherChanged()
{
RecalcConnectionPoint();
}
void RecalcConnectionPoint()
{
if (Connection.A == this)
{
if (Connection.B.ConnectionPoint.Left < this.Left)
{
ConnectionPoint = new Point(Left, Top + Height/2);
}
else
{
ConnectionPoint = new Point(Right, Top + Height/2);
}
}
}
}
然后,您可以将与Model类匹配的属性绑定到ViewModel类。然后操纵Model类中的数据将更新View。
你的容器和节点的样式将决定如何绘制它们,所以有一天你决定一个Node应该看起来像一个矩形......你改变一个样式而不必挖掘OnRender代码。< / p>
这就是你设计WPF程序的方法。
其他好处。
如果您要在Container上的某处放置一个“连接UI对象”,那么您将绑定它。您可以使用网格对齐ConnectionPointView,然后ConnectionPoint将自动更新。