Hello Walter
I have a NodeData class with a property called Icon, and a property called Status. The icon has a private setter and a public getter and is automatically set when the property Status gets set.
public class MyNodeData : GraphLinksModelNodeData<string> {
private PartStatus _status;
public PartStatus Status {
get { return this._status; }
set {
PartStatus oldStatus = this._status;
this._status = value;
this.IconName = this.IconName; // changes the icon depending on status
RaisePropertyChanged("Status", oldStatus, value);
}
}
private string _iconName;
public string IconName {
get { return this._iconName; }
set {
// grabs icon from cache depending on status, which is not interesting here
BitmapImage icon = ...
BitmapImage oldIcon = this.Icon;
this.Icon = icon;
RaisePropertyChanged("Icon", oldIcon, icon);
this._iconName = value;
}
}
public BitmapImage Icon { get; private set; }
// various other properties
...
}
with PartStatus being the following enum:
public enum PartStatus {
Default,
Selected,
Unselectable,
Disabled
}
The xaml looks like this:
<Style x:Key="StatusStackPanelStyle" TargetType="StackPanel">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Data.Status}" Value="{x:Static style:PartStatus.Default}">
<Setter Property="go:Part.Selectable" Value="{Binding Path=Data.IsSelectable}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Data.Status}" Value="{x:Static style:PartStatus.Selected}">
<Setter Property="go:Part.Selectable" Value="{Binding Path=Data.IsSelectable}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Data.Status}" Value="{x:Static style:PartStatus.Disabled}">
<Setter Property="go:Part.Selectable" Value="False" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Data.Status}" Value="{x:Static style:PartStatus.Unselectable}">
<Setter Property="go:Part.Selectable" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
<!-- I am leaving out all attributes of no interest as there are quite a lot -->
<DataTemplate x:Key="MyNodeTemplate">
<StackPanel Style="{StaticResource StatusStackPanelStyle}">
<go:SpotPanel>
<go:NodePanel>
<StackPanel>
<!-- this grid exists so an image can be displayed UniformToFill and at the same time be centered -->
<Grid>
<Image Source={Binding Path=Data.Icon} />
</Grid>
</StackPanel>
</go:NodePanel>
<!-- just like the StatusStackPanelStyle, this style sets Stroke, LinkableFrom/To and Cursor based on the Node's status -->
<Ellipse Style="{StaticResource StatusPortStyle}" />
<!-- there are many more Ports, which only differ in position --->
</go:SpotPanel>
<TextBlock Text="{Binding Path=Data.Text}" />
<!-- some more elements to show additional information -->
</StackPanel>
</DataTemplate>
When I select a node in the diagram, its Status
gets set to PartStatus.Selected
obviously. When I try to draw a link but cancel the operation, an InvalidOperationException
gets thrown, which shows nothing but “Icon” as error message but only if there was a change in Status
recently. The linking operation itself does not change the Status
. Checking the stack trace and overriding the ChangeDataValue
function of GraphLinksModel
showed me that the GraphLinksModel
tries to reset the changed properties of the node, which in case of the Icon
property is invalid of course due to the private setter. I solved this by checking for the property name for “Icon” in the function ChangeDataValue
before calling the base function but the question is, as the incorrect linking operation doesn’t change the node’s Status
and the Status
change happened beforehand and has nothing to do with the linking operation, why is it actually trying to revert these properties?