I am currently trying to display several “Logical Pages” with diagrams. And it seems to work when I try to statically use the goXAML Diagram control. However the drag/drop seems to stops working when I try to use the Diagram control in a TabControl.ContentTemplate. The visual trees look identical, the model properties all look set correctly, and yet the drop fails to drop.
And before anyone asks, yes I am setting Modifiable on the Model. :)
The Code in the view model looks like:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Xml.Linq;
using Northwoods.GoXam;
using Northwoods.GoXam.Model;
using Prism.Commands;
using Prism.Mvvm;
namespace GoDiagrams
{
public class RelayLogicViewModel : BindableBase
{
private LogicPage _selectedPage;
public GraphLinksModel<NodeData, string, string, WireData> Pallet { get; set; }
public ObservableCollection<LogicPage> LogicPages { get; set; } = new ObservableCollection<LogicPage>()
{
new LogicPage()
};
public LogicPage SelectedPage
{
get { return _selectedPage; }
set
{
_selectedPage = value;
OnPropertyChanged();
}
}
public RelayLogicViewModel()
{
// create pallet
Pallet = new GraphLinksModel<NodeData, string, string, WireData>();
Pallet.NodeCategoryPath = "GateType";
Pallet.LinksSource = new List<WireData>();
Pallet.NodesSource = new List<NodeData>()
{
new NodeData() { Figure=NodeFigure.Circle, GateType="Input", Key="Input", Category = "Input"},
new NodeData() { Figure=NodeFigure.Rectangle, GateType="Output", Key="Output", Category = "Output"}
};
SelectedPage = LogicPages.FirstOrDefault();
}
}
public class LogicPage : BindableBase
{
private bool _isInEditMode = false;
private bool _hasChanges = false;
private static int _count = 0;
public GraphLinksModel<NodeData, string, string, WireData> ConfiguredLogic { get; set; }
public DelegateCommand ToggleEditMode { get; set; }
public string PageName { get; set; } = "Diagram" + _count++;
public bool HasChanges
{
get { return _hasChanges; }
set
{
_hasChanges = value;
OnPropertyChanged();
}
}
public bool IsInEditMode
{
get { return _isInEditMode; }
set
{
_isInEditMode = value;
OnPropertyChanged();
}
}
public LogicPage()
{
ConfiguredLogic = new GraphLinksModel<NodeData, string, string, WireData>();
ConfiguredLogic.Modifiable = true;
ToggleEditMode = new DelegateCommand(() =>
{
IsInEditMode = !IsInEditMode;
HasChanges = IsInEditMode;
});
}
}
public class NodeData : GraphLinksModelNodeData<string>
{
private bool _value;
public string GateType { get; set; }
public NodeFigure Figure { get; set; }
public bool Value
{
get { return _value; }
set
{
bool old = _value;
if (old != value)
{
_value = value;
RaisePropertyChanged("Value", old, value);
}
}
}
public override XElement MakeXElement(XName n)
{
XElement e = base.MakeXElement(n);
e.Add(XHelper.Attribute("GateType", this.GateType, ""));
e.Add(XHelper.AttributeEnum<NodeFigure>("Figure", this.Figure, NodeFigure.Rectangle));
e.Add(XHelper.Attribute("Value", this.Value, false));
return e;
}
public override void LoadFromXElement(XElement e)
{
base.LoadFromXElement(e);
this.GateType = XHelper.Read("GateType", e, "");
this.Figure = XHelper.ReadEnum<NodeFigure>("Figure", e, NodeFigure.Rectangle);
this.Value = XHelper.Read("Value", e, false);
}
}
public class WireData : GraphLinksModelLinkData<string, string>
{
private bool _value;
public bool Value
{
get { return _value; }
set
{
bool old = _value;
if (old != value)
{
_value = value;
RaisePropertyChanged("Value", old, value);
}
}
}
}
}
And the XAML that Works looks like:
Notice that the TabControl has no bindings, and the TabItem DataContext is bound to the SelectedPage.
<Window x:Class="GoDiagrams.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:go="http://schemas.nwoods.com/GoXam"
xmlns:local="clr-namespace:GoDiagrams"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Window.Resources>
<SolidColorBrush x:Key="NodeLinks" Color="Gray" />
<SolidColorBrush x:Key="NodeFill" Color="LightGray" />
<SolidColorBrush x:Key="NodeForgroundText" Color="Black" />
<SolidColorBrush x:Key="NodeConnectors" Color="Black" />
<SolidColorBrush x:Key="NodeSelected" Color="Blue" />
<SolidColorBrush x:Key="NodeUnselected" Color="Black" />
<go:BooleanBrushConverter x:Key="NodeSelection" FalseBrush="{StaticResource NodeUnselected}" TrueBrush="{StaticResource NodeSelected}" />
<DataTemplate x:Key="NodeLink">
<go:LinkPanel>
<go:Link.Route>
<go:Route Curve="JumpOver" RelinkableFrom="True" RelinkableTo="True" Routing="AvoidsNodes" />
</go:Link.Route>
<go:LinkShape Stroke="{StaticResource NodeLinks}" StrokeThickness="2">
<go:LinkShape.Style>
<Style TargetType="go:LinkShape">
<Setter Property="StrokeThickness" Value="1" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="StrokeThickness" Value="3" />
</Trigger>
<DataTrigger Binding="{Binding Link.IsSelected}" Value="True">
<Setter Property="StrokeThickness" Value="2" />
</DataTrigger>
</Style.Triggers>
</Style>
</go:LinkShape.Style>
</go:LinkShape>
<Path go:LinkPanel.ToArrow="Standard" Fill="{StaticResource NodeLinks}" />
</go:LinkPanel>
</DataTemplate>
<go:DataTemplateDictionary x:Key="NodeTemplateDictionary">
<DataTemplate x:Key="Input">
<go:SpotPanel go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}">
<ToolTipService.ToolTip>
<TextBlock Text="{Binding Path=Data.Key}" />
</ToolTipService.ToolTip>
<go:NodePanel>
<Grid>
<go:NodeShape Width="50"
Height="50"
go:NodePanel.Figure="{Binding Path=Data.Figure}"
Fill="{StaticResource NodeFill}"
Stroke="{Binding Path=Node.IsSelected, Converter={StaticResource NodeSelection}}"
StrokeThickness="1" />
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{StaticResource NodeForgroundText}">Input</TextBlock>
</Grid>
</go:NodePanel>
<Rectangle Width="8"
Height="8"
go:Node.FromSpot="MiddleRight"
go:Node.LinkableFrom="True"
go:Node.LinkableMaximum="1"
go:Node.PortId=""
go:SpotPanel.Spot="MiddleRight"
Cursor="Hand"
Fill="{StaticResource NodeConnectors}" />
</go:SpotPanel>
</DataTemplate>
<DataTemplate x:Key="Output">
<go:SpotPanel go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}">
<ToolTipService.ToolTip>
<TextBlock Text="{Binding Path=Data.Key}" />
</ToolTipService.ToolTip>
<go:NodePanel>
<Grid>
<go:NodeShape Width="50"
Height="50"
go:NodePanel.Figure="{Binding Path=Data.Figure}"
Fill="{StaticResource NodeFill}"
Stroke="{Binding Path=Node.IsSelected, Converter={StaticResource NodeSelection}}"
StrokeThickness="1" />
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{StaticResource NodeForgroundText}">Output</TextBlock>
</Grid>
</go:NodePanel>
<Rectangle Width="8"
Height="8"
go:Node.FromSpot="MiddleLeft"
go:Node.LinkableMaximum="1"
go:Node.LinkableTo="True"
go:Node.PortId=""
go:SpotPanel.Spot="MiddleLeft"
Cursor="Hand"
Fill="{StaticResource NodeConnectors}" />
</go:SpotPanel>
</DataTemplate>
</go:DataTemplateDictionary>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="250" />
</Grid.ColumnDefinitions>
<TabControl Grid.Column="0">
<TabItem DataContext="{Binding SelectedPage}" Header="{Binding PageName}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Border Grid.Row="0" Margin="1" BorderBrush="{DynamicResource EditControlBorder}" BorderThickness="0,0,0,1">
<Button Margin="0,0,0,2"
HorizontalAlignment="Right"
Background="Blue"
Command="{Binding ToggleEditMode}"
Content="Edit"
Foreground="White">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding IsInEditMode}" Value="True">
<Setter Property="Background" Value="DarkGray" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Border>
<go:Diagram Name="TargetDiagram"
Grid.Row="1"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
AllowDrop="True"
GridSnapCellSize="10 10"
GridSnapEnabled="True"
LinkTemplate="{DynamicResource NodeLink}"
Model="{Binding ConfiguredLogic}"
NodeTemplateDictionary="{DynamicResource NodeTemplateDictionary}" />
</Grid>
</TabItem>
</TabControl>
<Grid Grid.Column="1">
<Border BorderBrush="Black" BorderThickness="1">
<go:Palette Name="SourcePalette"
AllowDrop="True"
FontFamily="Verdana"
FontSize="11"
FontWeight="Normal"
InitialScale="1"
Model="{Binding Pallet}"
NodeTemplateDictionary="{DynamicResource NodeTemplateDictionary}" />
</Border>
</Grid>
</Grid>
</Window>
While the code that isn’t working looks is pretty much just replace the TabControl above with:
Here the Tab Control ItemsSource is bound to the collection of pages, the Selected Item is the current tab, and the TabControl.ContentTemplate is set to the type of LogicPage data type.
<TabControl Grid.Column="0" ItemsSource="{Binding LogicPages}" SelectedItem="{Binding SelectedPage}">
<TabControl.ItemContainerStyle>
<Style BasedOn="{StaticResource {x:Type TabItem}}" TargetType="TabItem">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<DockPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock DockPanel.Dock="Left" Text="{Binding PageName}" />
<TextBlock DockPanel.Dock="Left" Text="*" Visibility="{Binding HasChanges, Converter={StaticResource BooleanToVisibilityConverter}}" />
</DockPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.ItemContainerStyle>
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type local:LogicPage}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Border Grid.Row="0" Margin="1" BorderBrush="{DynamicResource EditControlBorder}" BorderThickness="0,0,0,1">
<Button Margin="0,0,0,2"
HorizontalAlignment="Right"
Background="Blue"
Command="{Binding ToggleEditMode}"
Content="Edit"
Foreground="White">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding IsInEditMode}" Value="True">
<Setter Property="Background" Value="DarkGray" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Border>
<go:Diagram Name="TargetDiagram"
Grid.Row="1"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
AllowDrop="True"
GridSnapCellSize="10 10"
GridSnapEnabled="True"
LinkTemplate="{DynamicResource NodeLink}"
Model="{Binding ConfiguredLogic}"
NodeTemplateDictionary="{DynamicResource NodeTemplateDictionary}" />
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
Any ideas as to why dragging from my pallet stops working when I change it to a ContentTemplate? And any way to fix it so that it does work? I have a bunch of dynamic pages I need to load.
The UI looks like it is binding correctly and I see the diagram, just the can drop is coming back as false and I don’t understand why.
Thanks
James McDuffie
Bently Nevada, BHGE a GE Company
Senior Staff Software Architect
775-215-1076