It might be sufficient to give me the node template for the node whose bounds changed magically during the scroll.
Ok, this is our node user control:
<UserControl x:Class="Vision20.ConfigGui.Views.Documents.LogicConfig.ConfigNodeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:go="http://schemas.nwoods.com/GoXam"
xmlns:logicConfig="clr-namespace:Vision20.ConfigGui.Views.Documents.LogicConfig"
xmlns:port="clr-namespace:Vision20.ConfigGui.Views.Documents.Port"
xmlns:documents="clr-namespace:Vision20.ConfigGui.Views.Documents"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="130"
d:DataContext="{d:DesignInstance {x:Type go:Node}}"
Width="130"
x:Name="CurrentControl"
go:Node.Location="{Binding Path=Data.(documents:NodeDiagramModel.Location), Mode=TwoWay, UpdateSourceTrigger=Explicit}"
go:Node.LocationSpot="Center">
<UserControl.Resources>
<logicConfig:BooleanToVisibilityHiddenNegationConverter x:Key="BooleanToVisibilityHiddenNegationConverter" />
<documents:BoolInvertedToGridRowHeightConverter x:Key="BoolToGridRowHeight"></documents:BoolInvertedToGridRowHeightConverter>
</UserControl.Resources>
<go:NodePanel ToolTipService.ShowDuration="60000">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown" x:Uid="ML_0175">
<i:InvokeCommandAction Command="{Binding Path=Data.(documents:NodeDiagramModel.HandleNodeClickCommand)}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<go:NodePanel.ToolTip>
<StackPanel Orientation="Vertical" MaxWidth="300" MaxHeight="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition />
<RowDefinition Height="{Binding Path= Data.(documents:NodeDiagramModel.IsValidLogicController), Converter={StaticResource BoolToGridRowHeight}}" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Path=Data.(documents:NodeDiagramModel.Name)}" TextWrapping="Wrap" />
<TextBlock Grid.Row="1" Text="{Binding Path=Data.(documents:NodeDiagramModel.NodeId), StringFormat=ID: {0}}" />
<TextBlock Grid.Row="2" Text="{Binding Path=Data.(documents:NodeDiagramModel.Description), StringFormat={}{0}}" TextTrimming="WordEllipsis" TextWrapping="Wrap"
Visibility="{Binding Path= Data.(documents:NodeDiagramModel.IsClosed), Converter={StaticResource BooleanToVisibilityHiddenNegationConverter}}" />
<TextBlock Grid.Row="3" Text="{x:Static logicConfig:NodeIconNameHelper.Info}" FontStyle="Oblique" x:Uid="ML_0186"></TextBlock>
</Grid>
</StackPanel>
</go:NodePanel.ToolTip>
<Grid go:Node.Avoidable="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="22" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Node name -->
<TextBlock Grid.Row="0" Foreground="Black" Text="{Binding Path=Data.(documents:NodeDiagramModel.Name)}"
Visibility="{Binding Path=Data.(documents:NodeDiagramModel.IsClosed), Converter={StaticResource BooleanToVisibilityHiddenNegationConverter}}"
TextAlignment="Center" TextWrapping="Wrap" Height="Auto" MinHeight="0" Margin="4" />
<!-- Control frame -->
<Border Grid.Row="1" CornerRadius="10">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="2" x:Uid="ML_0194" />
<Setter Property="BorderBrush" Value="Black" x:Uid="ML_0195" />
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="AliceBlue" Offset="0.0" />
<GradientStop Color="LightBlue" Offset="1.0" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Part.IsSelected}" Value="True" x:Uid="ML_0200">
<Setter Property="Border.Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="10" RenderingBias="Performance" ShadowDepth="0" Color="DarkSalmon" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=Data.(documents:NodeDiagramModel.IsEnabled)}" Value="False" x:Uid="ML_0203">
<Setter Property="Border.Opacity" Value="0.34" x:Uid="ML_0204" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Data.(documents:NodeDiagramModel.IsMarked)}" Value="True" x:Uid="ML_0205">
<Setter Property="Border.Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="25" RenderingBias="Performance" ShadowDepth="0" Color="Magenta" />
</Setter.Value>
</Setter>
<DataTrigger.EnterActions>
<BeginStoryboard Name="BlinkAnimation">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0.1" AutoReverse="True" Duration="0:0:0.5" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="BlinkAnimation" x:Uid="ML_0211" />
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding Path=Data.(documents:NodeDiagramModel.IsValidLogicController)}" Value="False" x:Uid="ML_0212">
<Setter Property="Background">
<Setter.Value>
<DrawingBrush TileMode="Tile"
Viewport="0,0,30,30" ViewportUnits="Absolute"
Viewbox="0,0,30,30" ViewboxUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Brush="#ff7bd5ff" Thickness="10" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<Geometry>M0,0 L30,30 M15,-15 L45,15 M-15,15 L15,45</Geometry>
</GeometryDrawing.Geometry>
<GeometryDrawing.Brush>
<LinearGradientBrush>
<GradientStop Offset="0.0" Color="AliceBlue" />
<GradientStop Offset="1.0" Color="LightBlue" />
</LinearGradientBrush>
</GeometryDrawing.Brush>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<!-- Control main grid - margin-2 because of border -->
<Grid Margin="-2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Type name -->
<TextBlock Text="{Binding Path=Data.(documents:NodeDiagramModel.ReadableFamily)}" Grid.Row="0" Foreground="Black" TextAlignment="Center" Height ="Auto" TextWrapping="Wrap" Margin="10,2,10,2"
FontWeight="Bold" />
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<ItemsControl Grid.Column="0" ItemsSource="{Binding Path=Data.(documents:NodeDiagramModel.InputPorts)}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- Input template -->
<Grid Margin="0,5,0,5">
<Grid.RowDefinitions>
<!-- Pin -->
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<!-- Pin graphics -->
<ColumnDefinition Width="10" />
<!-- Pin name -->
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Pin graphics -->
<port:PortControl Grid.Row="0" Grid.Column="0" />
<!-- Pin name -->
<TextBlock Foreground="Black" Grid.Row="0" Grid.Column="1" Text="{Binding Name}"
VerticalAlignment="Center" Margin="5,0,5,0" FontSize="10" TextWrapping="Wrap" TextTrimming="CharacterEllipsis" Height="Auto" FontWeight="Bold" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- Output pins -->
<ItemsControl Grid.Column="1" ItemsSource="{Binding Path=Data.(documents:NodeDiagramModel.OutputPorts)}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,5,0,5">
<Grid.RowDefinitions>
<!-- Pin -->
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<!-- Pin name -->
<ColumnDefinition Width="*" />
<!-- Pin graphics -->
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<!-- Pin name -->
<TextBlock Grid.Row="0" Grid.Column="0" Foreground="Black" Text="{Binding Name}" VerticalAlignment="Center" TextAlignment="Right" Margin="5,0,-5,0" FontSize="10" TextWrapping="Wrap" TextTrimming="CharacterEllipsis" Height="Auto" FontWeight="Bold" />
<!-- Pin graphics -->
<port:PortControl Margin="8,0,-8,0" Grid.Row="0" Grid.Column="1" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
<Grid Grid.Row="2" Height="20">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Rectangle Grid.Column="1" Width="10" Height="10" HorizontalAlignment="Right" Fill="Gray" Margin="5" Stroke="Black" StrokeThickness="1" />
</Grid>
<Border Grid.Row="0" Margin="10,0,0,0" Grid.RowSpan="3" Background="Transparent" Visibility="{Binding Path=Data.(documents:NodeDiagramModel.IsClosed), Converter={StaticResource BooleanToVisibilityHiddenNegationConverter}}" />
</Grid>
</Border>
</Grid>
</go:NodePanel>
</UserControl>
And templates definitions:
<ResourceDictionary
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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:logicConfig="clr-namespace:Vision20.ConfigGui.Views.Documents.LogicConfig"
xmlns:commands="clr-namespace:Vision20.ConfigGui.Commands"
xmlns:documents="clr-namespace:Vision20.ConfigGui.Views.Documents"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:system="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d">
<system:Boolean x:Key="True">True</system:Boolean>
<system:Boolean x:Key="False">False</system:Boolean>
<logicConfig:ModelToInputPinWorkspaceDataConverter x:Key="ModelToInputPinWorkspaceDataConverter" />
<logicConfig:ModelToOutputPinWorkspaceDataConverter x:Key="ModelToOutputPinWorkspaceDataConverter" />
<logicConfig:BooleanToVisibilityHiddenNegationConverter x:Key="InvertBooleanToVisibilityConverter" />
<DataTemplate x:Key="InputPinManagementAdornmentTemplate">
<Grid go:Node.LocationElementName="Main">
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Data.(documents:NodeDiagramModel.IsClosed)}"
Value="True" x:Uid="ML_0112">
<Setter Property="Margin" Value="-6,-14,0,0" x:Uid="ML_0113" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Data.(documents:NodeDiagramModel.IsClosed)}"
Value="False" x:Uid="ML_0114">
<Setter Property="Margin" Value="-6,-28,0,0" x:Uid="ML_0115" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<Button Padding="0" Command="{x:Static commands:PinCommands.ManagePinsAmount}"
CommandParameter="{Binding Path=Data,Converter={StaticResource ModelToInputPinWorkspaceDataConverter}}"
Width="44" Height="34" Margin="1" Background="Transparent" BorderBrush="Transparent">
<StackPanel>
<Image Source="/Views/Documents/LogicConfig/pin_add_remove.png" />
</StackPanel>
</Button>
</StackPanel>
<go:SpotPanel x:Name="Main" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="InputOutputPinManagementAdornmentTemplate">
<Grid go:Node.LocationElementName="Main">
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Center">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Data.(documents:NodeDiagramModel.IsClosed)}"
Value="True" x:Uid="ML_0124">
<Setter Property="Margin" Value="0,-14,0,0" x:Uid="ML_0125" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Data.(documents:NodeDiagramModel.IsClosed)}"
Value="False" x:Uid="ML_0126">
<Setter Property="Margin" Value="0,-28,0,0" x:Uid="ML_0127" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<Button Padding="0" Command="{x:Static commands:PinCommands.ManagePinsAmount}"
CommandParameter="{Binding Path=Data,Converter={StaticResource ModelToInputPinWorkspaceDataConverter}}"
Width="44" Height="34" Margin="1" Background="Transparent" BorderBrush="Transparent">
<StackPanel>
<Image Source="/Views/Documents/LogicConfig/pin_add_remove.png" />
</StackPanel>
</Button>
</StackPanel>
<go:SpotPanel x:Name="Main" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="OutputPinManagementAdornmentTemplate">
<Grid go:Node.LocationElementName="Main">
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Right">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Data.(documents:NodeDiagramModel.IsClosed)}"
Value="True" x:Uid="ML_0136">
<Setter Property="Margin" Value="0,-14,-6,0" x:Uid="ML_0137" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Data.(documents:NodeDiagramModel.IsClosed)}"
Value="False" x:Uid="ML_0138">
<Setter Property="Margin" Value="0,-28,-6,0" x:Uid="ML_0139" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<Button Padding="0" Command="{x:Static commands:PinCommands.ManagePinsAmount}"
CommandParameter="{Binding Path=Data,Converter={StaticResource ModelToOutputPinWorkspaceDataConverter}}"
Width="44" Height="34" Margin="1" Background="Transparent" BorderBrush="Transparent">
<StackPanel>
<Image Source="/Views/Documents/LogicConfig/pin_add_remove.png" />
</StackPanel>
</Button>
</StackPanel>
<go:SpotPanel x:Name="Main" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="DefaultNodeTemplate" DataType="{x:Type go:Part}">
<logicConfig:ConfigNodeView />
</DataTemplate>
<go:DataTemplateDictionary x:Key="ConfigNodeTemplateStore" Default="{StaticResource DefaultNodeTemplate}">
<DataTemplate x:Key="Note" DataType="{x:Type go:Part}">
<Grid x:Name="NoteGrid" go:Part.SelectionElementName="Shape" go:Part.SelectionAdorned="True"
Background="Transparent"
go:Part.Resizable="True" go:Part.Text="{Binding Path=Data}"
go:Node.Location="{Binding Path=Data.(logicConfig:ConfigNoteDataModel.Location), Mode=TwoWay, UpdateSourceTrigger=Explicit}"
Width="{Binding Path=Data.(logicConfig:ConfigNoteDataModel.NodeWidth), Mode=TwoWay}"
Height="{Binding Path=Data.(logicConfig:ConfigNoteDataModel.NodeHeight), Mode=TwoWay}"
Cursor="Hand">
<go:NodePanel x:Name="parentElementName" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<go:NodeShape x:Name="Shape" go:NodePanel.Figure="TransmittalTape" Stroke="Black"
StrokeThickness="3"
Fill="{Binding Path=Data.(logicConfig:ConfigNoteDataModel.Color), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
MinWidth="120" MinHeight="100" MaxHeight="800" MaxWidth="800"
Width="{Binding Path=Data.(logicConfig:ConfigNoteDataModel.NodeWidth), Mode=TwoWay}"
Height="{Binding Path=Data.(logicConfig:ConfigNoteDataModel.NodeHeight), Mode=TwoWay}" IsHitTestVisible="False" />
<ScrollViewer VerticalScrollBarVisibility="Auto" Margin="5,5,5,5" Cursor="Pen" IsHitTestVisible="False">
<Grid IsHitTestVisible="False">
<xctk:RichTextBox
IsReadOnly="true" IsDocumentEnabled="True"
Cursor="Arrow" BorderThickness="0" VerticalAlignment="Stretch" Background="Transparent"
x:Name="_richTextBox"
IsHitTestVisible="False"
Text="{Binding Path=Data.(logicConfig:ConfigNoteDataModel.NoticeText), Mode=TwoWay}">
<xctk:RichTextBox.TextFormatter>
<xctk:RtfFormatter />
</xctk:RichTextBox.TextFormatter>
</xctk:RichTextBox>
</Grid>
</ScrollViewer>
</go:NodePanel>
</Grid>
</DataTemplate>
<DataTemplate x:Key="BinaryConverterBinDec" DataType="{x:Type go:Part}">
<logicConfig:ConfigNodeView go:Part.SelectionAdorned="True"
go:Part.SelectionAdornmentTemplate="{StaticResource InputPinManagementAdornmentTemplate}" />
</DataTemplate>
<DataTemplate x:Key="BinaryConverterDecBin" DataType="{x:Type go:Part}">
<logicConfig:ConfigNodeView go:Part.SelectionAdorned="True"
go:Part.SelectionAdornmentTemplate="{StaticResource OutputPinManagementAdornmentTemplate}" />
</DataTemplate>
<DataTemplate x:Key="BooleanClosedOr" DataType="{x:Type go:Part}">
<logicConfig:ConfigNodeView go:Part.SelectionAdorned="True"
go:Part.SelectionAdornmentTemplate="{StaticResource InputPinManagementAdornmentTemplate}" />
</DataTemplate>
<DataTemplate x:Key="BooleanClosedAnd" DataType="{x:Type go:Part}">
<logicConfig:ConfigNodeView go:Part.SelectionAdorned="True"
go:Part.SelectionAdornmentTemplate="{StaticResource InputPinManagementAdornmentTemplate}" />
</DataTemplate>
<DataTemplate x:Key="SwitchSEL" DataType="{x:Type go:Part}">
<logicConfig:ConfigNodeView go:Part.SelectionAdorned="True"
go:Part.SelectionAdornmentTemplate="{StaticResource InputOutputPinManagementAdornmentTemplate}" />
</DataTemplate>
<DataTemplate x:Key="MathematicalClosedSum" DataType="{x:Type go:Part}">
<logicConfig:ConfigNodeView go:Part.SelectionAdorned="True"
go:Part.SelectionAdornmentTemplate="{StaticResource InputPinManagementAdornmentTemplate}" />
</DataTemplate>
<DataTemplate x:Key="MathematicalClosedProduct" DataType="{x:Type go:Part}">
<logicConfig:ConfigNodeView go:Part.SelectionAdorned="True"
go:Part.SelectionAdornmentTemplate="{StaticResource InputPinManagementAdornmentTemplate}" />
</DataTemplate>
<DataTemplate x:Key="InputSelector" DataType="{x:Type go:Part}">
<logicConfig:ConfigNodeView go:Part.SelectionAdorned="True"
go:Part.SelectionAdornmentTemplate="{StaticResource InputPinManagementAdornmentTemplate}" />
</DataTemplate>
<DataTemplate x:Key="OutputSelector" DataType="{x:Type go:Part}">
<logicConfig:ConfigNodeView go:Part.SelectionAdorned="True"
go:Part.SelectionAdornmentTemplate="{StaticResource OutputPinManagementAdornmentTemplate}" />
</DataTemplate>
<DataTemplate x:Key="TextFormatter" DataType="{x:Type go:Part}">
<logicConfig:ConfigNodeView go:Part.SelectionAdorned="True"
go:Part.SelectionAdornmentTemplate="{StaticResource InputPinManagementAdornmentTemplate}" />
</DataTemplate>
<DataTemplate x:Key="Filter" DataType="{x:Type go:Part}">
<logicConfig:ConfigNodeView go:Part.SelectionAdorned="True"
go:Part.SelectionAdornmentTemplate="{StaticResource InputOutputPinManagementAdornmentTemplate}" />
</DataTemplate>
</go:DataTemplateDictionary>
</ResourceDictionary>
That is complicated. Still, almost all of it is details about the internals of the node, which should have no effect on the position or size of the whole node. Remember, the problem is that somehow the node’s Y position and height changed without the diagram’s DiagramPanel getting the chance to update its GoXam for WPF v3.
So the obvious unknown is what is happening in your UserControl. What does it do? Can you determine that its position and height are changing during scrolling?
Yes it is. After trying out - I think everything - I made a simple workaround with:
private void DiagramOnInitialLayoutCompleted(object sender, DiagramEventArgs e)
{
Task.Run(async () =>
{
await Task.Delay(100);
new WpfContext().BeginInvoke(() =>
{
Diagram.Padding = new Thickness(80, 130, 30, 130);
});
});
}
Changing Padding property fixes the problem - before any scroll operation. Original Padding value in xaml is 80, 30, 30, 30.
I’m glad you found a solution, but I don’t see how that could be a real solution.
At first I misread what you wrote and thought you were setting DiagramPanel.Padding, which would cause the DiagramPanel.DiagramBounds to be recomputed.
But your setting of Diagram.Padding really doesn’t affect the contents of the diagram at all.
And I don’t see why doing this on Diagram.InitialLayoutCompleted solves the problem after the user has made some changes to the diagram.