[英]Binding delay one step
好的,让我们看看我是否可以用英语很好地解释这一点。 这会很长,对不起,请耐心等待,我不知道如何缩短它。
我有两个实体作为 canvas 的UserControl
的子级,它们的拇指分别是UserControl
的子级。 我有一条通过拇指连接这些实体的折线,该折线是同一 canvas 的子代。
拇指有一个称为AnchorPoint
(拇指的中心)的依赖属性,折线的起点和终点通过各自的Start
和End
依赖属性绑定到该属性。
当我移动实体时,我以编程方式将AnchorPoint
属性更新到所需的点(拇指位置的中心),绑定会更改线点属性,当属性更改时,我会在折线上调用InvalidateMeasure
。 因此线随着实体移动。
和代码(我省略了不相关的代码):
UserControl
的连接拇指,孩子:
public partial class EntityConnectingThumb : UserControl, IChartEntityConnectingThumb, IObjectWithCancellableAction, IChartObjectCanBeRemoved, INotifyPropertyChanged
{
internal List<LineConnection> _LinesStarts = new List<LineConnection>();
internal List<LineConnection> _LinesEnds = new List<LineConnection>();
public Point AnchorPoint
{
get { return (Point)GetValue(AnchorPointProperty); }
private set { SetValue(AnchorPointProperty, value); }
}
public static readonly DependencyProperty AnchorPointProperty =
DependencyProperty.Register("AnchorPoint", typeof(Point), typeof(EntityConnectingThumb), new PropertyMetadata(default(Point)));
private void UpdateAnchorPoint()
{
if(_LinesStarts.Count > 0 || _LinesEnds.Count > 0)
Console.WriteLine("Update anchor point");
Size size = RenderSize;
Point ofs = new Point(size.Width / 2, size.Height / 2);
if (_LinesStarts.Count > 0 || _LinesEnds.Count > 0)
Console.WriteLine($"ofs = {ofs} {Environment.NewLine}Pre anchorpoint = {this.TranslatePoint(ofs, ChartCustomControl.Instance.ChartCanvas)}");
AnchorPoint = this.TranslatePoint(ofs, ChartCustomControl.Instance.ChartCanvas);
if (_LinesStarts.Count > 0 || _LinesEnds.Count > 0)
Console.WriteLine($"AnchorPoint= {AnchorPoint}");
}
public void MyBorderMovedTo()
{
if (_LinesStarts.Count > 0 || _LinesEnds.Count > 0)
Console.WriteLine("My border moved to");
UpdateAnchorPoint();
}
}
行 class,Canvas 的孩子( aChartArrowLineBase
实现Shape
):
public class LineConnection : aChartArrowLineBase, IChartObjectCanBeRemoved, IChartHaveHiddableThumbs
{
public ObservableCollection<aLineSegmentBase> Segments
{
get { return (ObservableCollection<aLineSegmentBase>)GetValue(SegmentsProperty); }
set { SetValue(SegmentsProperty, value); }
}
public static readonly DependencyProperty SegmentsProperty =
DependencyProperty.Register("Segments", typeof(ObservableCollection<aLineSegmentBase>), typeof(LineConnection), new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.AffectsMeasure, SegmentsPropertyChanged));
public new void InvalidateMeasure()
{
base.InvalidateMeasure();
_HitboxPolyLine.InvalidateMeasure();
}
/// <summary>
/// Gets a value that represents the Geometry of the ArrowPolyline.
/// </summary>
protected override Geometry DefiningGeometry
{
get
{
// Clear out the PathGeometry.
_Pathgeo.Figures.Clear();
_PathfigLine.Segments.Clear();
_HitboxPolyLine.Points.Clear();
// Try to avoid unnecessary indexing exceptions.
if (Segments.Count > 0)
{
// Define a PathFigure containing the points.
_PathfigLine.StartPoint = Segments[0].Start;
_PolysegLine.Points.Clear();
for (int i = 0; i < Segments.Count; i++)
{
var current = Segments[i];
switch(current._Type)
{
case LineSegmentTypesEnum.Start:
case LineSegmentTypesEnum.Normal:
_PolysegLine.Points.Add(current.Start);
_HitboxPolyLine.Points.Add(current.Start);
break;
case LineSegmentTypesEnum.Unique:
case LineSegmentTypesEnum.End:
_PolysegLine.Points.Add(current.Start);
_PolysegLine.Points.Add(current.End);
_HitboxPolyLine.Points.Add(current.Start);
_HitboxPolyLine.Points.Add(current.End);
break;
}
}
_PathfigLine.Segments.Add(_PolysegLine);
_Pathgeo.Figures.Add(_PathfigLine);
}
// Call the base property to add arrows on the ends.
return base.DefiningGeometry;
}
}
}
段基础 class, LineConnection
的孩子,这里是Start
和End
属性:
public abstract class aLineSegmentBase : FrameworkElement, IChartHaveHiddableThumbs, ILineSegmentBase
{
public aLineSegmentBase(LineSegmentTypesEnum Type, LineConnection connection, EntityConnectingThumb start, EntityConnectingThumb end)
{
Start = start.AnchorPoint;
End = end.AnchorPoint;
var b = new Binding()
{
Source = start,
Path = new PropertyPath(EntityConnectingThumb.AnchorPointProperty),
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
SetBinding(StartProperty, b);
b = new Binding()
{
Source = end,
Path = new PropertyPath(EntityConnectingThumb.AnchorPointProperty),
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
SetBinding(EndProperty, b);
_Loaded = true;
}
public Point Start
{
get { return (Point)GetValue(StartProperty); }
set { SetValue(StartProperty, value); }
}
public static readonly DependencyProperty StartProperty =
DependencyProperty.Register("Start", typeof(Point), typeof(aLineSegmentBase), new PropertyMetadata(default(Point), OnPointPropChanged));
public Point End
{
get { return (Point)GetValue(EndProperty); }
set { SetValue(EndProperty, value); }
}
public static readonly DependencyProperty EndProperty =
DependencyProperty.Register("End", typeof(Point), typeof(aLineSegmentBase), new PropertyMetadata(default(Point), OnPointPropChanged));
private static void OnPointPropChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((aLineSegmentBase)d).OnPointChanged();
}
private void OnPointChanged()
{
Console.WriteLine($"Line start changed= {p}");
if (!_Loaded)
return;
_Connection.InvalidateMeasure();
}
}
正如您所看到的, DefiningGeometry
迭代使用Start
和End
属性构建折线的线段,这些属性通过绑定链接到拇指锚点。
当锚点改变时,线点发生改变,在线上调用InvalidateMeasure
,重绘。
当我移动UserControls
时,我调用每个拇指UpdateAnchorPoint
方法并且一切正常,线条移动没有问题:
private void MovingThumb_PreviewMouseMove(object sender, MouseEventArgs e)
{
//Calculating new point p ...
Canvas.SetLeft(this, p.X - _MovingThumbPositionWhenClickedRelativeToCanvas.X);
Canvas.SetTop(this, p.Y - _MovingThumbPositionWhenClickedRelativeToCanvas.Y);
UpdateAnchorPoint();
CalculateSnapCoords(); //Here all thumb's UpdateAnchorPoint methods are called
///other stuff...
e.Handled = true;
}
internal void CalculateSnapCoords()
{
//Doing snap stuff...
DoActionAllConnectingThumbs(x => x.MyBorderMovedTo());
//More snap stuff...
}
但是现在我正在实现撤消/重做的东西,为此我使用此方法将UserControl
移动到它们的上一个(撤消)位置或下一个(重做)位置:
internal void AutomaticMoveTo(Point p)
{
Console.WriteLine($"Automatic move to = {p}");
Canvas.SetLeft(this, p.X);
Canvas.SetTop(this, p.Y);
UpdateAnchorPoint();
CalculateSnapCoords();
}
现在问题来了:这适用于实体,但行更新为“延迟一步”,我解释说:
1.-我按下撤消按钮,实体移动到上一个位置,线根本没有反应。
2.-我按下重做按钮,实体移动正确,但线移动到它应该移动的位置 1.-
3.- 再次撤消按钮,实体移动正确,线移动到 2.- 位置。
... 等等。
所以,绑定延迟了一步……??? 老实说,我是一个业余爱好者,但我什至不知道这是可能的。
我对此感到困惑,在我看来,绑定在值更改之前到达目标,因此新值不会传递给目标。 因此,当下一步发生时,目标取旧值而不是新值,并且新值存储在属性中而不传递给目标。
阅读控制台 output 似乎这正是正在发生的事情:
//---------------------------------------------------------------Last message moving entity
My border moved to
Update anchor point
ofs = 7,5;5
Pre anchorpoint = 660,80198019802;464,212871287129
AnchorPoint= 660,80198019802;464,212871287129
* Creating undo/redo command:_UndoMovingCoordinates = 609,39603960396;118,594059405941
; Last coordinates = 643,30198019802;442,212871287129
//---------------------------------------------------------------Here start undo/redo
*** UNDO move to = 609,39603960396;118,594059405941
Automatic move to = 609,39603960396;118,594059405941
My border moved to
Update anchor point
ofs = 7,5;5
Pre anchorpoint = 660,80198019802;464,212871287129
//---------------------------------------------------------------Here lacks a line, see below
AnchorPoint= 660,80198019802;464,212871287129
*** REDO move to = 643,30198019802;442,212871287129
Automatic move to = 643,30198019802;442,212871287129
My border moved to
Update anchor point
ofs = 7,5;5
Pre anchorpoint = 626,89603960396;140,594059405941
Line start changed= 626,89603960396;140,594059405941
AnchorPoint= 626,89603960396;140,594059405941
*** UNDO move to = 609,39603960396;118,594059405941
Automatic move to = 609,39603960396;118,594059405941
My border moved to
Update anchor point
ofs = 7,5;5
Pre anchorpoint = 660,80198019802;464,212871287129
Line start changed= 660,80198019802;464,212871287129
AnchorPoint= 660,80198019802;464,212871287129
您可以看到Line start changed=
行没有出现在第一条撤消消息中:第一次撤消更改不会更新Start
属性(或者至少没有启动属性更改事件)。 它保持了当时rest的一步延迟。
我尝试在Start
和End
属性绑定上使用UpdateSource
和UpdateTarget
,并在AnchorPoint
属性上使用PropertyChanged
,但没有任何变化。
我不能将AnchorPoint
属性直接绑定到连接拇指Canvas.LeftProperty
和Canvas.TopProperty
因为连接拇指不是UserControl
的孩子
我不知道发生了什么。 想法,提示,一些东西,都是受欢迎的。
我找到了解决方法。
问题是在折线DefiningGeometry
中绘制折线的点是每个线段的Start
和End
。 这些点绑定到它们各自拇指的AnchorPoint
属性。
当实体移动AnchorPoint
属性时,会像这样以编程方式更新...
private void UpdateAnchorPoint()
{
Size size = RenderSize;
Point ofs = new Point(size.Width / 2, size.Height / 2);
AnchorPoint = this.TranslatePoint(ofs, ChartCustomControl.Instance.ChartCanvas);
}
...锚点发生变化,起点/终点发生变化, PropertyChangedCallback
在线上调用InvalidateMeasure
并且线移动。
这在拖动实体时非常有效,但在仅通过Canvas.SetLeft
和Canvas.SetTop
更改实体位置一次时不起作用,这就是撤消/重做命令的作用:
internal void AutomaticMoveTo(Point p)
{
Canvas.SetLeft(this, p.X);
Canvas.SetTop(this, p.Y);
UpdateAnchorPoint();
CalculateSnapCoords();
}
由于某种原因,当实体的位置以这种方式更改时,开始/结束属性的PropertyChangedCallback
不会第一次被调用(不要问我,我不知道为什么),因此累积了“一步延迟”。
但是,如果我手动计算拇指中心并分配一个新创建的Point
object...
public void AutomaticMoveUpdateAnchorPoint()
{
double x = Canvas.GetLeft(MyBorder);
double y = Canvas.GetTop(MyBorder);
switch (Name)
{
case "ThTop":
x += (MyBorder.BorderContent.ActualWidth * 0.5d) + (MyBorder.RootGrid.ColumnDefinitions[0].ActualWidth * 1.75d);
y += (MyBorder.RootGrid.RowDefinitions[0].ActualHeight * 0.5d);
break;
case "ThBottom":
x += (MyBorder.BorderContent.ActualWidth * 0.5d) + (MyBorder.RootGrid.ColumnDefinitions[0].ActualWidth * 1.75d);
y += MyBorder.BorderContent.ActualHeight + (MyBorder.RootGrid.RowDefinitions[0].ActualHeight * 1.5d);
break;
case "ThLeft":
x += (MyBorder.RootGrid.ColumnDefinitions[0].ActualWidth);
y += (MyBorder.BorderContent.ActualHeight * 0.5d) + (MyBorder.RootGrid.RowDefinitions[0].ActualHeight);
break;
case "ThRight":
x += (MyBorder.RootGrid.ColumnDefinitions[1].ActualWidth) + (MyBorder.RootGrid.ColumnDefinitions[0].ActualWidth * 2.25d);
y += (MyBorder.BorderContent.ActualHeight * 0.5d) + (MyBorder.RootGrid.RowDefinitions[0].ActualHeight);
break;
}
AnchorPoint = new Point(x, y);
}
...它再次完美运行。 绑定再次正常工作,并且再次正常调用PropertyChangedCallback
。
我不知道为什么会这样。 绑定是标准的TwoWay
, UpdateSourceTrigger.PropertyChanged
,我知道最初的TranslatePoint
行也创建了一个新的Point
object。 也许它没有反映 canvas 的变化? 我不知道,我不明白为什么会发生这种情况,但是,我有解决方法,我使用新方法,一切正常。
我会把它留在这里,以防有人可以使用它,甚至找到原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.