支持添加中间节点

This commit is contained in:
艾竹
2023-01-21 22:01:10 +08:00
parent c4ab1a6355
commit 2e396d687b
8 changed files with 249 additions and 219 deletions

View File

@@ -33,19 +33,8 @@ namespace AIStudio.Wpf.DiagramDesigner.Controls
{ {
if (this.DataContext is ConnectorPoint point) if (this.DataContext is ConnectorPoint point)
{ {
double minLeft = double.MaxValue; point.X += e.HorizontalChange;
double minTop = double.MaxValue; point.Y += e.VerticalChange;
double left = point.X;
double top = point.Y;
minLeft = double.IsNaN(left) ? 0 : Math.Min(left, minLeft);
minTop = double.IsNaN(top) ? 0 : Math.Min(top, minTop);
double deltaHorizontal = Math.Max(-minLeft, e.HorizontalChange);
double deltaVertical = Math.Max(-minTop, e.VerticalChange);
point.X += deltaHorizontal;
point.Y += deltaVertical;
} }
} }

View File

@@ -32,7 +32,12 @@ namespace AIStudio.Wpf.DiagramDesigner
double targetAngle = TargetMarkerAdjustement(route, link.ColorViewModel.RightArrowSize); double targetAngle = TargetMarkerAdjustement(route, link.ColorViewModel.RightArrowSize);
BezierSpline.GetCurveControlPoints(route, out var firstControlPoints, out var secondControlPoints); BezierSpline.GetCurveControlPoints(route, out var firstControlPoints, out var secondControlPoints);
var paths = new string[firstControlPoints.Length];
DoShift(route, link);
DoShift(firstControlPoints, link);
DoShift(secondControlPoints, link);
var paths = new string[firstControlPoints.Length];
for (var i = 0; i < firstControlPoints.Length; i++) for (var i = 0; i < firstControlPoints.Length; i++)
{ {

View File

@@ -7,7 +7,7 @@ namespace AIStudio.Wpf.DiagramDesigner
{ {
public static PointBase[] Normal(IDiagramViewModel _, ConnectorViewModel link) public static PointBase[] Normal(IDiagramViewModel _, ConnectorViewModel link)
{ {
return link.Vertices.Select(v => (PointBase)v).ToArray(); return link.Vertices.Select(v => v.MiddlePosition).ToArray();
} }
} }
} }

View File

@@ -542,7 +542,7 @@
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding EditCommand}" CommandParameter="{Binding }" /> <MouseBinding MouseAction="LeftDoubleClick" Command="{Binding EditCommand}" CommandParameter="{Binding }" />
</Canvas.InputBindings> </Canvas.InputBindings>
<!--<Polyline x:Name="poly" <!--<Polyline x:Name="poly"
Points="{Binding Path=ConnectionPoints, Converter={x:Static s:ConnectionPointConverter.Instance}}" Points="{Binding Path=Vertices, Converter={x:Static s:ConnectionPointConverter.Instance}}"
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
StrokeThickness="{Binding ColorViewModel.LineWidth}" StrokeThickness="{Binding ColorViewModel.LineWidth}"
StrokeDashArray="{Binding ColorViewModel.LineDashStyle,Converter={StaticResource LineDashConverter}}" />--> StrokeDashArray="{Binding ColorViewModel.LineDashStyle,Converter={StaticResource LineDashConverter}}" />-->
@@ -600,7 +600,7 @@
</c:DragThumb.InputBindings> </c:DragThumb.InputBindings>
</c:DragThumb> </c:DragThumb>
<s:PointContainer x:Name="PART_PointContainer" Style="{StaticResource innerConnectorContainer}" ItemsSource="{Binding ConnectionPoints}" Visibility="Collapsed"> <s:PointContainer x:Name="PART_PointContainer" Style="{StaticResource innerConnectorContainer}" ItemsSource="{Binding Vertices}" Visibility="Collapsed">
<s:PointContainer.ItemTemplate> <s:PointContainer.ItemTemplate>
<DataTemplate> <DataTemplate>
<Grid> <Grid>
@@ -616,6 +616,7 @@
</Style> </Style>
</s:PointContainer.Resources> </s:PointContainer.Resources>
</s:PointContainer> </s:PointContainer>
<Rectangle Fill="#7F243859" Opacity="0.5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Visibility="{Binding ShouldInsertAnchor, Converter={StaticResource BooleanToVisibilityConverter}}"> <Rectangle Fill="#7F243859" Opacity="0.5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Visibility="{Binding ShouldInsertAnchor, Converter={StaticResource BooleanToVisibilityConverter}}">
<i:Interaction.Behaviors> <i:Interaction.Behaviors>
<s:ControlMouseLeftButtonDownCommandBehavior Command="{Binding AddVertexCommand}" /> <s:ControlMouseLeftButtonDownCommandBehavior Command="{Binding AddVertexCommand}" />

View File

@@ -91,14 +91,14 @@ namespace AIStudio.Wpf.DiagramDesigner
} }
} }
public PointBase Position public virtual PointBase Position
{ {
get get
{ {
return new PointBase(Left, Top); return new PointBase(Left, Top);
} }
} }
public PointBase MiddlePosition => new PointBase(Left + ConnectorWidth / 2, Top + ConnectorHeight / 2); public virtual PointBase MiddlePosition => new PointBase(Left + ConnectorWidth / 2, Top + ConnectorHeight / 2);
private double connectorWidth = 8; private double connectorWidth = 8;
public double ConnectorWidth public double ConnectorWidth

View File

@@ -46,7 +46,8 @@ namespace AIStudio.Wpf.DiagramDesigner
{ {
this.ColorViewModel.RightArrowPathStyle = ArrowPathStyle.None; this.ColorViewModel.RightArrowPathStyle = ArrowPathStyle.None;
} }
ColorViewModel.PropertyChanged += ColorViewModel_PropertyChanged; ColorViewModel.PropertyChanged += ConnectorViewModel_PropertyChanged;
this.PropertyChanged += ConnectorViewModel_PropertyChanged;
var routetype = GlobalType.AllTypes.Where(p => typeof(IRouter).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == RouterMode); var routetype = GlobalType.AllTypes.Where(p => typeof(IRouter).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == RouterMode);
Router = routetype != null ? (System.Activator.CreateInstance(routetype) as IRouter) : new RouterNormal(); Router = routetype != null ? (System.Activator.CreateInstance(routetype) as IRouter) : new RouterNormal();
@@ -57,18 +58,12 @@ namespace AIStudio.Wpf.DiagramDesigner
this.SourceConnectorInfo = sourceConnectorInfo; this.SourceConnectorInfo = sourceConnectorInfo;
this.SinkConnectorInfo = sinkConnectorInfo; this.SinkConnectorInfo = sinkConnectorInfo;
DeleteConnectionCommand = new SimpleCommand(DeleteConnection); DeleteConnectionCommand = new SimpleCommand(DeleteConnection);
AddVertexCommand = new SimpleCommand(AddVertex); AddVertexCommand = new SimpleCommand(AddVertex);
} }
private void ColorViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) private void ConnectorViewModel_PropertyChanged1(object sender, PropertyChangedEventArgs e)
{ {
if (e.PropertyName == nameof(ColorViewModel.LeftArrowPathStyle) || throw new NotImplementedException();
e.PropertyName == nameof(ColorViewModel.LeftArrowSizeStyle) ||
e.PropertyName == nameof(ColorViewModel.RightArrowPathStyle) ||
e.PropertyName == nameof(ColorViewModel.RightArrowSizeStyle))
{
UpdatePathGeneratorResult();
}
} }
public override SelectableDesignerItemBase ToXmlObject() public override SelectableDesignerItemBase ToXmlObject()
@@ -90,6 +85,7 @@ namespace AIStudio.Wpf.DiagramDesigner
return typeof(ConnectionItem); return typeof(ConnectionItem);
} }
#region
private PointBase _sourceA; private PointBase _sourceA;
public PointBase SourceA public PointBase SourceA
{ {
@@ -99,10 +95,7 @@ namespace AIStudio.Wpf.DiagramDesigner
} }
set set
{ {
if (SetProperty(ref _sourceA, value)) SetProperty(ref _sourceA, value);
{
UpdateArea();
}
} }
} }
@@ -115,37 +108,7 @@ namespace AIStudio.Wpf.DiagramDesigner
} }
set set
{ {
if (SetProperty(ref _sourceB, value)) SetProperty(ref _sourceB, value);
{
UpdateArea();
}
}
}
private ObservableCollection<ConnectorPoint> _connectionPoints = new ObservableCollection<ConnectorPoint>();
public ObservableCollection<ConnectorPoint> ConnectionPoints
{
get
{
return _connectionPoints;
}
private set
{
if (_connectionPoints != null)
{
foreach (var connectionPoint in _connectionPoints)
{
connectionPoint.PropertyChanged -= new WeakINPCEventHandler(ConnectionPoint_PropertyChanged).Handler;
}
}
SetProperty(ref _connectionPoints, value);
if (_connectionPoints != null)
{
foreach (var connectionPoint in _connectionPoints)
{
connectionPoint.PropertyChanged += new WeakINPCEventHandler(ConnectionPoint_PropertyChanged).Handler;
}
}
} }
} }
@@ -210,12 +173,7 @@ namespace AIStudio.Wpf.DiagramDesigner
} }
private set private set
{ {
RectangleBase oldarea = _area; SetProperty(ref _area, value);
if (SetProperty(ref _area, value))
{
UpdatePathGeneratorResult();
OutTextItemLocation(oldarea, value);
}
} }
} }
@@ -266,7 +224,19 @@ namespace AIStudio.Wpf.DiagramDesigner
} }
//待完善这两处 //待完善这两处
public List<LinkVertexModel> Vertices { get; } = new List<LinkVertexModel>(); private ObservableCollection<LinkVertexModel> _vertices = new ObservableCollection<LinkVertexModel>();
public ObservableCollection<LinkVertexModel> Vertices
{
get
{
return _vertices;
}
private set
{
SetProperty(ref _vertices, value);
}
}
public List<LinkLabelModel> Labels { get; set; } = new List<LinkLabelModel>(); public List<LinkLabelModel> Labels { get; set; } = new List<LinkLabelModel>();
public virtual Dictionary<string, string> PropertiesSetting public virtual Dictionary<string, string> PropertiesSetting
@@ -289,11 +259,7 @@ namespace AIStudio.Wpf.DiagramDesigner
} }
set set
{ {
if (SetProperty(ref _sourceConnectorInfo, value)) SetProperty(ref _sourceConnectorInfo, value);
{
SourceA = PointHelper.GetPointForConnector(_sourceConnectorInfo);
(_sourceConnectorInfo.DataItem as INotifyPropertyChanged).PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler;
}
} }
} }
@@ -306,14 +272,8 @@ namespace AIStudio.Wpf.DiagramDesigner
} }
set set
{ {
if (SetProperty(ref _sinkConnectorInfo, value)) SetProperty(ref _sinkConnectorInfo, value);
{
SourceB = _sinkConnectorInfo.Position;
if (_sinkConnectorInfo is FullyCreatedConnectorInfo)
{
(((FullyCreatedConnectorInfo)_sinkConnectorInfo).DataItem as INotifyPropertyChanged).PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler;
}
}
} }
} }
@@ -350,6 +310,95 @@ namespace AIStudio.Wpf.DiagramDesigner
} }
public bool IsPortless => SourceConnectorInfo?.DataItem?.Connectors?.Count() == 0; public bool IsPortless => SourceConnectorInfo?.DataItem?.Connectors?.Count() == 0;
#endregion
#region
public SimpleCommand DeleteConnectionCommand
{
get; set;
}
public SimpleCommand AddVertexCommand
{
get; set;
}
#endregion
private void ConnectorViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (sender is ConnectorViewModel)
{
switch (e.PropertyName)
{
case nameof(SourceA):
case nameof(SourceB):
UpdateArea();
break;
case nameof(Area):
UpdatePathGeneratorResult();
if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs)
{
OutTextItemLocation((RectangleBase)valuePropertyChangedEventArgs.OldValue, (RectangleBase)valuePropertyChangedEventArgs.NewValue);
}
break;
case nameof(Vertices):
foreach (var vertice in Vertices)
{
vertice.PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler;
}
break;
case nameof(SourceConnectorInfo):
SourceA = PointHelper.GetPointForConnector(SourceConnectorInfo);
(SourceConnectorInfo.DataItem as INotifyPropertyChanged).PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler;
break;
case nameof(SinkConnectorInfo):
SourceB = SinkConnectorInfo.Position;
if (SinkConnectorInfo is FullyCreatedConnectorInfo)
{
(((FullyCreatedConnectorInfo)SinkConnectorInfo).DataItem as INotifyPropertyChanged).PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler;
}
break;
}
}
else if (sender is ColorViewModel)
{
if (e.PropertyName == nameof(ColorViewModel.LeftArrowPathStyle) ||
e.PropertyName == nameof(ColorViewModel.LeftArrowSizeStyle) ||
e.PropertyName == nameof(ColorViewModel.RightArrowPathStyle) ||
e.PropertyName == nameof(ColorViewModel.RightArrowSizeStyle))
{
UpdatePathGeneratorResult();
}
}
else if (sender is DesignerItemViewModelBase)
{
switch (e.PropertyName)
{
case nameof(DesignerItemViewModelBase.ItemHeight):
case nameof(DesignerItemViewModelBase.ItemWidth):
case nameof(DesignerItemViewModelBase.Left):
case nameof(DesignerItemViewModelBase.Top):
SourceA = PointHelper.GetPointForConnector(this.SourceConnectorInfo);
if (IsFullConnection)
{
SourceB = PointHelper.GetPointForConnector(this.SinkConnectorInfoFully);
}
break;
}
}
else if (sender is LinkVertexModel)
{
switch (e.PropertyName)
{
case nameof(ConnectorPoint.Left):
case nameof(ConnectorPoint.Top):
UpdatePathGeneratorResult();
break;
}
}
}
private void UpdateArea() private void UpdateArea()
{ {
@@ -405,18 +454,19 @@ namespace AIStudio.Wpf.DiagramDesigner
case ConnectorOrientation.Left: case ConnectorOrientation.Left:
{ {
EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X, PathGeneratorResult.TargetMarkerPosition.Y - ColorViewModel.RightArrowSize / 2); EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X, PathGeneratorResult.TargetMarkerPosition.Y - ColorViewModel.RightArrowSize / 2);
break; } break;
}
case ConnectorOrientation.Top: case ConnectorOrientation.Top:
{ {
EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X - ColorViewModel.RightArrowSize / 2, PathGeneratorResult.TargetMarkerPosition.Y); EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X - ColorViewModel.RightArrowSize / 2, PathGeneratorResult.TargetMarkerPosition.Y);
break; break;
} }
case ConnectorOrientation.Right: case ConnectorOrientation.Right:
{ {
EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X - ColorViewModel.RightArrowSize, PathGeneratorResult.TargetMarkerPosition.Y - ColorViewModel.RightArrowSize / 2); EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X - ColorViewModel.RightArrowSize, PathGeneratorResult.TargetMarkerPosition.Y - ColorViewModel.RightArrowSize / 2);
break; break;
} }
case ConnectorOrientation.Bottom: case ConnectorOrientation.Bottom:
{ {
EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X - ColorViewModel.RightArrowSize / 2, PathGeneratorResult.TargetMarkerPosition.Y - ColorViewModel.RightArrowSize); EndPoint = new PointBase(PathGeneratorResult.TargetMarkerPosition.X - ColorViewModel.RightArrowSize / 2, PathGeneratorResult.TargetMarkerPosition.Y - ColorViewModel.RightArrowSize);
@@ -433,48 +483,6 @@ namespace AIStudio.Wpf.DiagramDesigner
EndAngle = PathGeneratorResult.TargetMarkerAngle; EndAngle = PathGeneratorResult.TargetMarkerAngle;
} }
private void ConnectorViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "ItemHeight":
case "ItemWidth":
case "Left":
case "Top":
SourceA = PointHelper.GetPointForConnector(this.SourceConnectorInfo);
if (IsFullConnection)
{
SourceB = PointHelper.GetPointForConnector(this.SinkConnectorInfoFully);
}
break;
}
}
private void ConnectionPoint_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "Left":
case "Top":
RaisePropertyChanged(nameof(ConnectionPoints));
break;
}
}
public SimpleCommand DeleteConnectionCommand
{
get; set;
}
public SimpleCommand AddVertexCommand
{
get; set;
}
private void DeleteConnection(object args) private void DeleteConnection(object args)
{ {
if (this.Parent is IDiagramViewModel) if (this.Parent is IDiagramViewModel)
@@ -489,7 +497,10 @@ namespace AIStudio.Wpf.DiagramDesigner
MouseButtonEventArgs mosueArg = ((EventToCommandArgs)parameter).EventArgs as MouseButtonEventArgs; MouseButtonEventArgs mosueArg = ((EventToCommandArgs)parameter).EventArgs as MouseButtonEventArgs;
var position = mosueArg.GetPosition(((EventToCommandArgs)parameter).Sender as IInputElement); var position = mosueArg.GetPosition(((EventToCommandArgs)parameter).Sender as IInputElement);
ConnectionPoints.Add(new ConnectorPoint(position.X, position.Y)); var vertice = new LinkVertexModel(this, new PointBase(position.X, position.Y));
vertice.PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler;
Vertices.Add(vertice);
UpdatePathGeneratorResult();
if (!((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)) if (!((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control))
{ {
@@ -497,58 +508,6 @@ namespace AIStudio.Wpf.DiagramDesigner
} }
} }
protected override void ExecuteEditCommand(object param)
{
if (this.OutTextItem != null) return;
AddText("");
}
public void AddText(string text)
{
if (this.Parent is IDiagramViewModel)
{
var diagramVM = this.Parent as IDiagramViewModel;
TextDesignerItemViewModel textitem = new TextDesignerItemViewModel();
textitem.ItemWidth = Double.NaN;
textitem.ItemHeight = double.NaN;
//if (this.PathMode == DrawMode.ConnectingLineBoundary.ToString())
//{
// var mid = (int)(ConnectionPoints.Count / 2);
// var p = PathGenerators.SegmentMiddlePoint(ConnectionPoints[mid - 1], ConnectionPoints[mid]);
// textitem.Left = this.Area.Left + p.X + 2;
// textitem.Top = this.Area.Top + p.Y - 15;
//}
//else
{
textitem.Left = this.Area.Left + this.Area.Width / 2 - 16;
textitem.Top = this.Area.Top + this.Area.Height / 2 - 5;
}
textitem.Watermark = null;
textitem.ZIndex = diagramVM.Items.Count;
textitem.ParentId = this.Id;
textitem.ParentItem = this;
textitem.ColorViewModel.FillColor = new ColorObject() { Color = Colors.White };
textitem.Text = text;
diagramVM.DirectAddItemCommand.Execute(textitem);
this.OutTextItem = textitem;
}
}
public void OutTextItemLocation(RectangleBase oldArea, RectangleBase newArea)
{
if (this.OutTextItem is TextDesignerItemViewModel text)
{
var oldpoint = new PointBase(oldArea.Left + oldArea.Width / 2, oldArea.Top + oldArea.Height / 2);
var newpoint = new PointBase(newArea.Left + newArea.Width / 2, newArea.Top + newArea.Height / 2);
text.Left = text.Left + newpoint.X - oldpoint.X;
text.Top = text.Top + newpoint.Y - oldpoint.Y;
}
}
private (PointBase? source, PointBase? target) FindConnectionPoints(PointBase[] route) private (PointBase? source, PointBase? target) FindConnectionPoints(PointBase[] route)
{ {
if (IsPortless) // Portless if (IsPortless) // Portless
@@ -624,7 +583,58 @@ namespace AIStudio.Wpf.DiagramDesigner
return minPoint; return minPoint;
} }
#region
protected override void ExecuteEditCommand(object param)
{
if (this.OutTextItem != null) return;
AddText("");
}
public void AddText(string text)
{
if (this.Parent is IDiagramViewModel)
{
var diagramVM = this.Parent as IDiagramViewModel;
TextDesignerItemViewModel textitem = new TextDesignerItemViewModel();
textitem.ItemWidth = Double.NaN;
textitem.ItemHeight = double.NaN;
//if (this.PathMode == DrawMode.ConnectingLineBoundary.ToString())
//{
// var mid = (int)(ConnectionPoints.Count / 2);
// var p = PathGenerators.SegmentMiddlePoint(ConnectionPoints[mid - 1], ConnectionPoints[mid]);
// textitem.Left = this.Area.Left + p.X + 2;
// textitem.Top = this.Area.Top + p.Y - 15;
//}
//else
{
textitem.Left = this.Area.Left + this.Area.Width / 2 - 16;
textitem.Top = this.Area.Top + this.Area.Height / 2 - 5;
}
textitem.Watermark = null;
textitem.ZIndex = diagramVM.Items.Count;
textitem.ParentId = this.Id;
textitem.ParentItem = this;
textitem.ColorViewModel.FillColor = new ColorObject() { Color = Colors.White };
textitem.Text = text;
diagramVM.DirectAddItemCommand.Execute(textitem);
this.OutTextItem = textitem;
}
}
public void OutTextItemLocation(RectangleBase oldArea, RectangleBase newArea)
{
if (this.OutTextItem is TextDesignerItemViewModel text)
{
var oldpoint = new PointBase(oldArea.Left + oldArea.Width / 2, oldArea.Top + oldArea.Height / 2);
var newpoint = new PointBase(newArea.Left + newArea.Width / 2, newArea.Top + newArea.Height / 2);
text.Left = text.Left + newpoint.X - oldpoint.X;
text.Top = text.Top + newpoint.Y - oldpoint.Y;
}
}
#endregion
} }
} }

View File

@@ -16,5 +16,15 @@ namespace AIStudio.Wpf.DiagramDesigner
get; get;
} }
public override PointBase Position
{
get
{
return new PointBase(Parent.Area.Left + Left, Parent.Area.Top + Top);
}
}
public override PointBase MiddlePosition => new PointBase(Parent.Area.Left + Left + ConnectorWidth / 2, Parent.Area.Top + Top + ConnectorHeight / 2);
} }
} }

View File

@@ -17,40 +17,6 @@ namespace AIStudio.Wpf.DiagramDesigner
/// </summary> /// </summary>
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Checks if a property already matches a desired value. Sets the property and
/// notifies listeners only when necessary.
/// </summary>
/// <typeparam name="T">Type of the property.</typeparam>
/// <param name="storage">Reference to a property with both getter and setter.</param>
/// <param name="value">Desired value for the property.</param>
/// <param name="propertyName">Name of the property used to notify listeners. This
/// value is optional and can be provided automatically when invoked from compilers that
/// support CallerMemberName.</param>
/// <returns>True if the value was changed, false if the existing value matched the
/// desired value.</returns>
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(storage, value))
return false;
if (propertyName == "IsSelected")
{
}
else if (this.ContainsProperty("IsReadOnly"))
{
if (object.Equals(this.GetPropertyValue("IsReadOnly"), true))
return false;
}
var old = storage;
storage = value;
RaisePropertyChanged(propertyName, old, value);
return true;
}
private Dictionary<string, object> _oldDic = new Dictionary<string, object>(); private Dictionary<string, object> _oldDic = new Dictionary<string, object>();
public void SetOldValue<T>(T value, string propertyName, string guid = null) public void SetOldValue<T>(T value, string propertyName, string guid = null)
{ {
@@ -78,6 +44,44 @@ namespace AIStudio.Wpf.DiagramDesigner
} }
} }
/// <summary>
/// Checks if a property already matches a desired value. Sets the property and
/// notifies listeners only when necessary.
/// </summary>
/// <typeparam name="T">Type of the property.</typeparam>
/// <param name="storage">Reference to a property with both getter and setter.</param>
/// <param name="value">Desired value for the property.</param>
/// <param name="propertyName">Name of the property used to notify listeners. This
/// value is optional and can be provided automatically when invoked from compilers that
/// support CallerMemberName.</param>
/// <returns>True if the value was changed, false if the existing value matched the
/// desired value.</returns>
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(storage, value))
return false;
if (propertyName == "IsSelected")
{
}
else if (this.ContainsProperty("IsReadOnly"))
{
if (object.Equals(this.GetPropertyValue("IsReadOnly"), true))
return false;
}
if (propertyName == "Area")
{
}
var old = storage;
storage = value;
RaisePropertyChanged(propertyName, old, value);
return true;
}
/// <summary> /// <summary>
/// Checks if a property already matches a desired value. Sets the property and /// Checks if a property already matches a desired value. Sets the property and
/// notifies listeners only when necessary. /// notifies listeners only when necessary.
@@ -93,11 +97,22 @@ namespace AIStudio.Wpf.DiagramDesigner
/// desired value.</returns> /// desired value.</returns>
protected virtual bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null) protected virtual bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null)
{ {
if (EqualityComparer<T>.Default.Equals(storage, value)) return false; if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
if (propertyName == "IsSelected")
{
}
else if (this.ContainsProperty("IsReadOnly"))
{
if (object.Equals(this.GetPropertyValue("IsReadOnly"), true))
return false;
}
var old = storage;
storage = value; storage = value;
onChanged?.Invoke(); onChanged?.Invoke();
RaisePropertyChanged(propertyName); RaisePropertyChanged(propertyName, old, value);
return true; return true;
} }