It’s not working!
I implemented it as in the Socket class, but the ChangeDataValue was not fired. I found out that the PropertyChanged Event is always null, but the DataContext is set.
I have no idea.
FIY this is just a demo program to proof things for the greater application.
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using Northwoods.GoXam;
using Northwoods.GoXam.Model;
using Northwoods.GoXam.Tool;
namespace WpfApplication54WalterDnD
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private Point? startPoint;
public MainWindow()
{
InitializeComponent();
AllNodes = new ObservableCollection<MyNode>();
DataContext = this;
}
public ObservableCollection<MyNode> AllNodes { get; set; }
private void MouseLeftButtonDownExecute(MouseButtonEventArgs arg)
{
if (arg.ButtonState == MouseButtonState.Pressed)
{
startPoint = arg.GetPosition(null);
}
}
private void MouseMoveExecute(MouseEventArgs arg)
{
if (arg.LeftButton == MouseButtonState.Pressed && startPoint != null)
{
var mousePos = arg.GetPosition(null);
Vector diff = startPoint.Value - mousePos;
if (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)
{
ListBox listBox = Part.FindAncestor<ListBox>((Visual) arg.OriginalSource);
if (listBox != null)
{
ListBoxItem listBoxItem = Part.FindAncestor<ListBoxItem>((Visual) arg.OriginalSource);
if (listBoxItem != null)
{
var data = listBoxItem.Content;
Debug.WriteLine(data);
DataObject dragData = new DataObject(DataFormats.StringFormat, data);
DragDrop.DoDragDrop(listBox, dragData, DragDropEffects.Copy);
Debug.WriteLine("MouseMove");
}
}
}
}
else
{
startPoint = null;
}
}
private void ListBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MouseLeftButtonDownExecute(e);
}
private void ListBox_MouseMove(object sender, MouseEventArgs e)
{
MouseMoveExecute(e);
}
private void myDiagram_ExternalObjectsDropped(object sender, DiagramEventArgs e)
{
myDiagram.Focus();
}
}
public class CustomDraggingTool : DraggingTool
{
private MyNode addedNode;
protected override void DragOver(Point pt, bool moving, bool copying)
{
base.DragOver(pt, moving, copying);
Part part = Diagram.Panel.FindElementsAt(pt, Part.FindAncestor<Part>, p => !Diagram.SelectedParts.Contains(p), SearchLayers.Parts).FirstOrDefault();
if (part != null)
{
Debug.WriteLine("Dragging over: " + part);
}
}
protected override void DropOnto(Point pt)
{
base.DropOnto(pt);
Part part = Diagram.Panel.FindElementsAt(pt, Part.FindAncestor<Part>, p => !Diagram.SelectedParts.Contains(p), SearchLayers.Parts).FirstOrDefault();
if (part != null)
{
Debug.WriteLine("Drop onto: " + part);
var myNode = Diagram.SelectedNode.Data as MyNode;
if (myNode != null)
{
var node = part.Data as MyNode;
if (node != null)
{
Diagram.StartTransaction("Change");
node.Name = myNode.Name;
node.Displays[0].Color = Colors.Red;
Diagram.CommitTransaction("Change");
DoCancel();
}
}
}
addedNode = null;
}
public override void DoDragEnter(DragEventArgs e)
{
var droppedItem = e.Data.GetData(DataFormats.StringFormat) as String;
if (droppedItem != null && addedNode == null)
{
var dataCollection = Diagram.Model.CreateDataCollection();
addedNode = new MyNode(droppedItem);
dataCollection.AddNode(addedNode);
e.Data.SetData(Diagram.Model.DataFormat, dataCollection);
}
}
public override void DoDragLeave(DragEventArgs e)
{
if (e.Effects == DragDropEffects.None)
{
addedNode = null;
}
base.DoDragLeave(e);
}
}
public class MyModel : GraphLinksModel<MyNode, Guid, String, MyLink>
{
public MyModel()
{
Modifiable = true;
HasUndoManager = true;
}
}
[Serializable]
public class MyNode : GraphLinksModelNodeData<Guid>
{
public MyNode(String name)
{
_Name = name;
Key = Guid.NewGuid();
Displays = new ObservableCollection<Display>();
Displays.Add(new Display() { Parent = this, Color = Colors.Aqua });
}
private String _Name;
private ObservableCollection<Display> displays;
public string Name
{
get { return _Name; }
set
{
if (_Name != value)
{
var old = _Name;
_Name = value;
RaisePropertyChanged("Name", old, value);
}
}
}
public ObservableCollection<Display> Displays
{
get { return displays; }
set
{
if (displays == value) return;
var oldValue = displays;
displays = value;
RaisePropertyChanged("Displays" , oldValue, value);
}
}
public override object Clone()
{
MyNode result = (MyNode) base.Clone();
//result.Displays = new ObservableCollection<Display>(Displays.Select(d => new Display() { Color = d.Color }));
return result;
}
public override void ChangeDataValue(ModelChangedEventArgs e, bool undo)
{
Display display = e.Data as Display;
if (display != null)
display.ChangeDataValue(e, undo);
else
base.ChangeDataValue(e, undo);
Debug.WriteLine(e.PropertyName + " " + e.OldValue + " " + e.NewValue);
}
}
[Serializable]
public class Display : INotifyPropertyChanged, IChangeDataValue, ICloneable
{
public MyNode Parent;
private Color color;
public Color Color
{
get { return color; }
set
{
if (value.Equals(color)) return;
var oldValue = Color;
color = value;
RaisePropertyChanged("Color", oldValue, value);
Debug.WriteLine("ColorChanged");
}
}
[field: NonSerializedAttribute()]
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(String pname, Object oldval, Object newval)
{
ModelChangedEventArgs e = new ModelChangedEventArgs(pname, this, oldval, newval);
// implement INotifyPropertyChanged:
if (this.PropertyChanged != null) this.PropertyChanged(this, e);
// implement support for model and undo/redo:
if (this.Parent != null) this.Parent.OnPropertyChanged(e);
}
public void ChangeDataValue(ModelChangedEventArgs e, bool undo)
{
switch (e.PropertyName)
{
case "Color":
Color = (Color) e.GetValue(undo);
break;
}
}
public object Clone()
{
return MemberwiseClone();
}
}
public class MyLink : GraphLinksModelLinkData<Guid, Guid>
{
}
}
<Window x:Class="WpfApplication54WalterDnD.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:go="http://schemas.nwoods.com/GoXam"
xmlns:wpfApplication54WalterDnD="clr-namespace:WpfApplication54WalterDnD"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<go:StringBrushConverter x:Key="StringBrushConverter" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="118*" />
<ColumnDefinition Width="399*" />
</Grid.ColumnDefinitions>
<ListBox PreviewMouseLeftButtonDown="ListBox_PreviewMouseLeftButtonDown" MouseMove="ListBox_MouseMove">
<ListBox.Items>
<ListBoxItem>SimpleNode</ListBoxItem>
<ListBoxItem>ComplexNode</ListBoxItem>
<ListBoxItem>SuperNode</ListBoxItem>
</ListBox.Items>
</ListBox>
<go:Diagram Grid.Column="1" x:Name="myDiagram" AllowDrop="True" Background="Bisque"
NodesSource="{Binding AllNodes}"
VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch"
GridSnapCellSize="5 5"
GridSnapEnabled="True"
GridVisible="True" ExternalObjectsDropped="myDiagram_ExternalObjectsDropped">
<go:Diagram.DraggingTool>
<wpfApplication54WalterDnD:CustomDraggingTool />
</go:Diagram.DraggingTool>
<go:Diagram.Model>
<wpfApplication54WalterDnD:MyModel />
</go:Diagram.Model>
<go:Diagram.NodeTemplate>
<DataTemplate>
<TextBlock Text="{Binding Data.Name}" go:Part.SelectionAdorned="True" Background="{Binding Data.Displays[0].Color, Converter={StaticResource StringBrushConverter}}"
go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}" />
</DataTemplate>
</go:Diagram.NodeTemplate>
<go:Diagram.GridPattern>
<go:GridPattern CellSize="10 10">
<Path Stroke="LightGray" StrokeThickness="0.2" go:GridPattern.Figure="HorizontalLine" />
<Path Stroke="LightGray" StrokeThickness="0.2" go:GridPattern.Figure="VerticalLine" />
<Path Stroke="White" StrokeThickness="0.2" go:GridPattern.Figure="HorizontalLine" go:GridPattern.Interval="5" />
<Path Stroke="White" StrokeThickness="0.2" go:GridPattern.Figure="VerticalLine" go:GridPattern.Interval="5" />
<Path Stroke="Black" StrokeThickness="0.3" go:GridPattern.Figure="HorizontalLine" go:GridPattern.Interval="10" />
<Path Stroke="Black" StrokeThickness="0.3" go:GridPattern.Figure="VerticalLine" go:GridPattern.Interval="10" />
</go:GridPattern>
</go:Diagram.GridPattern>
</go:Diagram>
</Grid>
</Window>
Drag a Node over an existing to changed color and than try ctrl-z. It only changes the Text if it’s necessary (e.g. drop complex node over simple node).