Hi everyone,
I had an issue when activating the UndoManager for my model. And I was able to reproduce the same issue with the UpdateDemo provided by GoWPFDemo.
Mainly, what I’am doing is changing the node’s color depending on whether it is linked from or not.
Here is the UpdateDemo code with my changes:
<code>
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Northwoods.GoXam.Model;
namespace UpdateDemo {
public partial class UpdateDemo : UserControl {
public UpdateDemo() {
InitializeComponent();
// create a couple of nodes initially connected by a link
var nodes = new ObservableCollection<TestData>() {
new TestData() { Key="N1", Location=new Point(0, 0) },
new TestData() { Key="N2", Location=new Point(100, 100) }
};
var links = new ObservableCollection<TestLink>() {
new TestLink() { From="N1", To="N2", Text="N1-N2" }
};
var model = new TestModel();
model.NodesSource = nodes;
model.LinksSource = links;
model.Modifiable = true;
model.HasUndoManager = true;
model.Changed += model_Changed; // update the log and TreeView
// a background double-click creates a new node
myDiagram.Model = model;
myDiagram.ClickCreatingTool.DoubleClick = true;
myDiagram.ClickCreatingTool.PrototypeData = new TestData() { Key="I1" };
// setup up the second Diagram that shares the single Model
myDiagram2.Model = model;
myDiagram2.ClickCreatingTool.DoubleClick = true;
myDiagram2.ClickCreatingTool.PrototypeData = new TestData() { Key="I1" };
}
void model_Changed(object sender, ModelChangedEventArgs e) {
// add an entry to the log
if (e.Change >= 0)
{
if (ShowChanges.IsChecked == true)
{
myLog.Text += e.ToString() + Environment.NewLine;
myScroller.ScrollToVerticalOffset(9e9);
}
}
else
{
if (ShowLayouts.IsChecked == true ||
(!"Layout".Equals(e.Data) && !"DelayedRouting".Equals(e.Data)))
{
myLog.Text += e.ToString() + Environment.NewLine;
myScroller.ScrollToVerticalOffset(9e9);
}
}
// add an item to the tree view showing the UndoManager state
if (e.Change == ModelChange.CommittedTransaction)
{
UndoManager.CompoundEdit cedit = e.OldValue as UndoManager.CompoundEdit;
if (cedit != null)
{
if (this.EditToRedo != null)
{
// remove from TreeView all transactions starting with this.EditToRedo
ItemCollection coll = myTreeView.Items;
int idx = coll.IndexOf(this.EditToRedo);
if (idx >= 0)
{
while (coll.Count > idx) coll.RemoveAt(idx);
}
this.EditToRedo = null;
}
// add a TreeViewItem representing the completed transaction
TreeViewItem citem = new TreeViewItem();
citem.Tag = cedit;
citem.Header = cedit.Name;
// all of the changes within the transaction are tree view children
foreach (IUndoableEdit edit in cedit.Edits)
{
TreeViewItem eitem = new TreeViewItem();
eitem.Tag = edit;
eitem.Header = edit.ToString();
citem.Items.Add(eitem);
}
myTreeView.Items.Add(citem);
}
}
else if (e.Change == ModelChange.FinishedUndo || e.Change == ModelChange.FinishedRedo)
{
// unselect any currently selected transaction
if (this.EditToRedo != null)
{
this.EditToRedo.IsSelected = false;
this.EditToRedo = null;
}
IUndoableEdit nextedit = myDiagram.Model.UndoManager.EditToRedo;
if (nextedit != null)
{
// find the next edit to redo, and select it
foreach (TreeViewItem item in myTreeView.Items)
{
if (item.Tag == nextedit) {
item.IsSelected = true;
this.EditToRedo = item;
break;
}
}
}
}
}
private TreeViewItem EditToRedo { get; set; }
private void ClearLog(object sender, RoutedEventArgs e) {
myLog.Text = "";
}
}
public class TestModel : GraphLinksModel<TestData, String, String, TestLink> {
// initialize each link''s text label to a string
protected override TestLink InsertLink(TestData fromdata, string fromparam, TestData todata, string toparam) {
TestLink link = new TestLink() { From=fromdata.Key, FromPort=fromparam, To=todata.Key,ToPort=toparam};
link.Text = link.From + "-" + link.To;
var links = this.LinksSource as IList<TestLink>;
if (link != null) links.Add(link);
fromdata.LinkedFrom = true;
return link;
}
}
public class TestData : GraphLinksModelNodeData<String>
{
private bool _linkedFrom;
public bool LinkedFrom
{
get { return _linkedFrom; }
set
{
var oldColor = DataColor;
_linkedFrom = value;
RaisePropertyChanged("DataColor", oldColor, DataColor);
}
}
public Brush DataColor
{
get
{
return LinkedFrom ? Brushes.Green : Brushes.DarkRed;
}
}
public TestData()
{
LinkedFrom = false;
}
}
public class TestLink : GraphLinksModelLinkData<String, String> { }
}
</code>
As you may have noticed, I only modified the TestData class and added a line in the overridden InsertLink method to set the LinkedFrom flag.
In the xaml file I changed the NodeTemplate to this:
<code>
<DataTemplate x:Key="NodeTemplate">
<go:NodePanel Sizing="Auto"
go:Part.SelectionAdorned="True"
go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}">
<go:NodeShape go:NodePanel.Figure="Pentagon"
Fill="{Binding Path=Data.DataColor}" Stroke="Black" StrokeThickness="1"
go:Node.PortId=""
go:Node.LinkableFrom="True" go:Node.LinkableTo="True" />
<TextBlock Text="{Binding Path=Data.Key}" Margin="10"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</go:NodePanel>
</DataTemplate>
</code>
Now whenever the Undo has to remove a link I get the following exception:
An unhandled exception of type ‘System.InvalidOperationException’ occurred in Northwoods.GoWPF.dll
Additional information: DataColor
Is this a bug in GoXam? or how can I fix this?
Many thanks