Hi Walter,
In the official project changes are notify only if properties have been changed, so this point is already managed (I’ve done it quick and dirty).
If I’ve implemented a IsExpanded property, it’s to be able to “synchronized” group expanded status for the same data on different diagram.
From now I’ve never used StartTransaction/CommitTransaction (what’s bad), so regarding to your remarks this point, what could be the consequences, if I do not use it ? In any case I have fix it.
I’m modifying the demo to solve all your remarks (I hope), but (if I’m not wrong) except by setting the command in the main view (in this case class MainWindow) I do not see how I should use the Start/Commit transaction principle as Property is on the model and Diagram on the view.
Here are the modified class:
<Window x:Class="TestGoWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestGoWpf"
xmlns:gowpf="http://schemas.nwoods.com/GoXam"
mc:Ignorable="d"
Title="MainWindow" Height="800" Width="1200">
<Window.Resources>
<DataTemplate x:Key="GroupTemplate" DataType="{x:Type local:NodeData}">
<Border x:Name="myBorder"
CornerRadius="0" BorderThickness="2" BorderBrush="Black" Background="Orange"
gowpf:Part.SelectionAdorned="True"
gowpf:Group.LocationElementName="myGroupPanel"
gowpf:Group.IsSubGraphExpanded="{Binding Path=Data.Key.IsExpanded, Mode=TwoWay}"
gowpf:Group.WasSubGraphExpanded="{Binding Path=Data.Key.WasExpanded, Mode=TwoWay}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<StackPanel Orientation="Vertical" HorizontalAlignment="Left">
<TextBlock Text="{Binding Path=Data.Key.Name}" FontWeight="Bold" />
<WrapPanel>
<TextBlock Text="IsExpanded : "/>
<TextBlock Text="{Binding Path=Data.Key.IsExpanded}"/>
</WrapPanel>
<WrapPanel>
<TextBlock Text="WasExpanded : "/>
<TextBlock Text="{Binding Path=Data.Key.WasExpanded}"/>
</WrapPanel>
<WrapPanel>
<!-- This is the only way I see to be able to use command and Start/Commit -->
<Button x:Name="myCollapseExpandButtonCommand"
Command="{Binding CommandExpandCollapse, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:MainWindow}}"
CommandParameter="{Binding}"
Content="Expand/Collapse"
Margin="0 0 5 0" />
<!-- Version with button (same as your Grouping.xaml example)-->
<Button x:Name="myCollapseExpandButtonCommand2"
Click="ButtonBase_OnClick"
Content="Expand/Collapse"
Margin="0 0 5 0" />
</WrapPanel>
</StackPanel>
</StackPanel>
<gowpf:GroupPanel x:Name="myGroupPanel"
Grid.Row="1"
Padding="5"
MinWidth="20"
MinHeight="20"
Background="LightGray" >
</gowpf:GroupPanel>
</Grid>
<gowpf:Group.Layout >
<gowpf:GridLayout WrappingColumn="4" />
</gowpf:Group.Layout>
</Border>
</DataTemplate>
</Window.Resources>
<Grid Margin="0 10">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel>
<WrapPanel>
<Button Click="AddRootToModel" Content="Add Root to Model"/>
<Button Click="AddSubGroup" Content="Add to Selected"/>
<Button Click="DoLayout" Content="Do Layout"/>
<WrapPanel>
<TextBlock x:Name="Width" Text="{Binding }" />
</WrapPanel>
</WrapPanel>
</StackPanel>
<gowpf:Diagram Grid.Row="1"
x:Name="myDiagram"
Padding="10"
GroupTemplate="{StaticResource GroupTemplate}"
AllowMove="True"
Background="WhiteSmoke">
<gowpf:Diagram.Layout>
<gowpf:GridLayout WrappingColumn="4" ></gowpf:GridLayout>
</gowpf:Diagram.Layout>
</gowpf:Diagram>
</Grid>
</Window>
using Northwoods.GoXam;
using Northwoods.GoXam.Model;
using System;
using System.Collections.ObjectModel;
using System.Data.Common;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace TestGoWpf
{
internal class CommandBase : ICommand
{
#region properties
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
private Func<object, bool> _CanExecute;
private Action<object> _Execute;
#endregion properties
#region ctor
public CommandBase(Func<object, bool> canExecute, Action<object> execute)
{
_CanExecute = canExecute;
_Execute = execute;
}
#endregion ctor
#region ICommand
public bool CanExecute(object parameter)
{
return _CanExecute(parameter);
}
public void Execute(object parameter)
{
_Execute(parameter);
}
#endregion ICommand
}
public class MyNodeKey : DependencyObject
{
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(MyNodeKey), new PropertyMetadata(""));
public bool IsExpanded
{
get { return (bool) GetValue(IsExpandedProperty); }
set { SetValue(IsExpandedProperty, value); }
}
public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register(
"IsExpanded", typeof(bool), typeof(MyNodeKey), new PropertyMetadata(true));
public bool WasExpanded
{
get { return (bool) GetValue(WasExpandedProperty); }
set { SetValue(WasExpandedProperty, value); }
}
public static readonly DependencyProperty WasExpandedProperty = DependencyProperty.Register(
"WasExpanded", typeof(bool), typeof(MyNodeKey), new PropertyMetadata(true));
public MyNodeKey(string name)
{
Name = name;
}
public override string ToString()
{
return Name;
}
}
public class NodeData : GraphModelNodeData<MyNodeKey>
{
public NodeData(MyNodeKey key, NodeData parent = null)
{
Key = key;
}
}
public partial class MainWindow : Window
{
public ICommand CommandExpandCollapse { get; set; }
ObservableCollection<NodeData> NodesSource = new ObservableCollection<NodeData>();
private int i = 0;
public MainWindow()
{
InitializeComponent();
var model = new GraphModel<NodeData, MyNodeKey>();
model.NodesSource = NodesSource;
myDiagram.Model = model;
model.Modifiable = true;
CommandExpandCollapse = new CommandBase(CanExecuteCommandExpandCollapse, ExecuteCommandExpandCollapse);
}
private void AddSubGroup(object sender, RoutedEventArgs e)
{
NodeData Root = null;
if (myDiagram.SelectedPart is Group)
{
Root = myDiagram.SelectedPart.Data as NodeData;
}
if (Root is null)
{
return;
}
var subGroup = new NodeData(new MyNodeKey("SubGroup_" + (++i)), Root)
{
IsSubGraph = true,
SubGraphKey = Root.Key,
};
myDiagram.StartTransaction("Add SubGroup");
NodesSource.Add(subGroup);
myDiagram.CommitTransaction("Add SubGroup");
myDiagram.LayoutDiagram();
}
private void AddRootToModel(object sender, RoutedEventArgs e)
{
var rootNode = new NodeData(new MyNodeKey("Group_" + i))
{
IsSubGraph = true,
};
NodesSource.Add(rootNode);
myDiagram.LayoutDiagram();
}
private void DoLayout(object sender, RoutedEventArgs e)
{
myDiagram.LayoutDiagram();
}
public bool CanExecuteCommandExpandCollapse(object parameter)
{
return true;
}
public void ExecuteCommandExpandCollapse(object parameter)
{
// For me here I loose the benefit of using a Command
if (parameter is NodeData nodeData)
{
myDiagram.StartTransaction("ExpandCoLlapse");
nodeData.Key.IsExpanded = !nodeData.Key.IsExpanded;
myDiagram.CommitTransaction("ExpandCoLlapse");
}
}
// version with click
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Button button = (Button) sender;
Group sg = Part.FindAncestor<Group>(button);
if (sg != null)
{
NodeData nodeData = (NodeData) sg.Data;
myDiagram.StartTransaction("CollapseExpand");
nodeData.Key.IsExpanded = !nodeData.Key.IsExpanded;
myDiagram.CommitTransaction("CollapseExpand");
}
}
}
}