Closed nickhudson4 closed 1 year ago
Hi,
10+ nodes is definitely not a large amount of nodes for Nodify. I would suggest to upgrade to the latest version or at least the next version if that's possible, and see if the issue persists.
You can also try setting the Connector.EnableOptimizations static field to false before rendering the editor.
Hi. Thanks for the reply!
I updated to the latest version and tried messing with the Connector.EnableOptimizations field with no luck.
For reference, this is what our MainWindow.xaml looks like
<Window
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:nodify="https://miroiu.github.io/nodify"
xmlns:local="clr-namespace:UI"
xmlns:ports="clr-namespace:UI.ViewModels.Ports"
xmlns:models="clr-namespace:UI.ViewModels"
xmlns:Converters="clr-namespace:AdonisUI.Converters;assembly=AdonisUI"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
x:Name="window"
x:Class="UI.MainWindow"
mc:Ignorable="d"
Title="Controller" Height="768" Width="1200"
Icon="Assets/***.ico" MinWidth="600" MinHeight="400">
<Window.Resources>
<Converters:MathConverter x:Key="MathConverter"/>
<DrawingBrush x:Key="GridDrawingBrush"
TileMode="Tile"
ViewportUnits="Absolute"
Viewport="0 0 15 15"
Transform="{Binding AppliedTransform, ElementName=Editor}">
<DrawingBrush.Drawing>
<GeometryDrawing Geometry="M0,0 L0,1 0.03,1 0.03,0.03 1,0.03 1,0 Z"
Brush="#333337" />
</DrawingBrush.Drawing>
</DrawingBrush>
<SolidColorBrush x:Key="ConditionalNodeBrush" Color="#A60048"/>
<SolidColorBrush x:Key="EventHandlerNodeBrush" Color="#FFC3710D"/>
<local:DataTypeConverter x:Key="DataTypeConverter"></local:DataTypeConverter>
<local:HeaderDataTemplateSelector x:Key="MySelector"/>
</Window.Resources>
<Window.Style>
<Style TargetType="{x:Type Window}" BasedOn="{StaticResource {x:Type Window}}"/>
</Window.Style>
<Grid x:Name="grid" Background="#1E1E1E">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" MinWidth="200" MaxWidth="{Binding ActualWidth, Converter={StaticResource MathConverter}, ConverterParameter=x-200, ElementName=grid, Mode=OneWay}" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="0*" />
</Grid.ColumnDefinitions>
<local:ProjectView Graphs="{Binding ProjectGraphs}"/>
<local:GraphControlsView Grid.Column="2" Panel.ZIndex="1"/>
<GridSplitter Grid.Column="1" Width="8" HorizontalAlignment="Stretch" Background="#FF3D3D4C" />
<nodify:NodifyEditor Grid.Column="2" x:Name="Editor"
DataContext="{Binding SelectedGraph}"
Connections="{Binding Connections}"
SelectedItems="{Binding SelectedNodes}"
ConnectionCompletedCommand="{Binding CreateConnectionCommand}"
DisconnectConnectorCommand="{Binding DeleteConnectionCommand}"
ItemsSource="{Binding Nodes}">
<nodify:NodifyEditor.Resources>
<Style TargetType="{x:Type nodify:NodeInput}"
BasedOn="{StaticResource {x:Type nodify:NodeInput}}">
<Setter Property="Header"
Value="{Binding}" />
<Setter Property="Anchor"
Value="{Binding Anchor, Mode=OneWayToSource}" />
<Setter Property="IsConnected"
Value="{Binding IsConnected}" />
<Style.Triggers>
<DataTrigger
Binding="{Binding Type}"
Value="IntegerPort">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"
Margin="5 0 0 0" />
<TextBox Text="{Binding Value}"
IsEnabled="True" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger
Binding="{Binding Type}"
Value="EmptyPort">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"
Margin="5 0 0 0" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger
Binding="{Binding Type}"
Value="VectorPort">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"
Margin="5 0 0 0" />
<TextBox Text="{Binding X}"
IsEnabled="True" />
<TextBox Text="{Binding Y}"
IsEnabled="True" />
<TextBox Text="{Binding Z}"
IsEnabled="True" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type nodify:NodeOutput}"
BasedOn="{StaticResource {x:Type nodify:NodeOutput}}">
<Setter Property="Header"
Value="{Binding}" />
<Setter Property="Anchor"
Value="{Binding Anchor, Mode=OneWayToSource}" />
<Setter Property="IsConnected"
Value="{Binding IsConnected}" />
<Style.Triggers>
<DataTrigger
Binding="{Binding Type}"
Value="IntegerPort">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"
Margin="0 0 5 0" />
<TextBox Text="{Binding Value}"
IsEnabled="True" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger
Binding="{Binding Type}"
Value="EmptyPort">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"
Margin="0 0 5 0" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger
Binding="{Binding Type}"
Value="VectorPort">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"
Margin="0 0 5 0" />
<TextBox Text="{Binding X}"
IsEnabled="True" />
<TextBox Text="{Binding Y}"
IsEnabled="True" />
<TextBox Text="{Binding Z}"
IsEnabled="True" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type nodify:Node}">
<Style.Triggers>
<DataTrigger
Binding="{Binding Category}"
Value="{x:Static models:Category.Conditional}">
<Setter Property="HeaderBrush" Value="{StaticResource ConditionalNodeBrush}"/>
</DataTrigger>
<DataTrigger
Binding="{Binding Category}"
Value="{x:Static models:Category.EventHandler}">
<Setter Property="HeaderBrush" Value="{StaticResource EventHandlerNodeBrush}"/>
</DataTrigger>
</Style.Triggers>
</Style>
<DataTemplate DataType="{x:Type models:Node}">
<nodify:Node Header="{Binding}"
HeaderTemplateSelector="{StaticResource MySelector}"
ToolTip="{Binding Description}"
Input="{Binding Inputs}"
Output="{Binding Outputs}"
/>
</DataTemplate>
<DataTemplate x:Key="DefaultHeader">
<TextBlock Text="{Binding Path=Name}"></TextBlock>
</DataTemplate>
<DataTemplate x:Key="ConditionalHeader">
<StackPanel Orientation="Horizontal">
<iconPacks:PackIconVaadinIcons Kind="RoadBranch" Margin="0, 0, 5, 0" />
<TextBlock Text="{Binding Path=Name}"></TextBlock>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="EventHandlerHeader">
<StackPanel Orientation="Horizontal">
<iconPacks:PackIconUnicons Kind="KeyboardAlt" Margin="0, 0, 5, 0" />
<TextBlock Text="{Binding Path=Name}"></TextBlock>
</StackPanel>
</DataTemplate>
</nodify:NodifyEditor.Resources>
<nodify:NodifyEditor.Background>
<StaticResource ResourceKey="GridDrawingBrush"/>
</nodify:NodifyEditor.Background>
<nodify:NodifyEditor.InputBindings>
<KeyBinding Key="Delete" Command="{Binding DeleteSelectionCommand}" />
</nodify:NodifyEditor.InputBindings>
<nodify:NodifyEditor.ConnectionTemplate>
<DataTemplate DataType="{x:Type models:Connection}">
<nodify:Connection Source="{Binding Output.Anchor}"
Target="{Binding Input.Anchor}"
SourceOffset="0 0"
TargetOffset="0 0"
OffsetMode="None"
/>
</DataTemplate>
</nodify:NodifyEditor.ConnectionTemplate>
<nodify:NodifyEditor.ItemContainerStyle>
<Style TargetType="{x:Type nodify:ItemContainer}"
BasedOn="{StaticResource {x:Type nodify:ItemContainer}}">
<Setter Property="Location"
Value="{Binding Location}" />
<Setter Property="IsSelected"
Value="{Binding IsSelected}" />
</Style>
</nodify:NodifyEditor.ItemContainerStyle>
</nodify:NodifyEditor>
</Grid>
</Window>
This seems to be a hardware issue. (and WPF struggling to render lots of controls at once)
TL;DR: see a possible fix at the end
The camera panning is nothing more than updating a RenderTransform. You can validate this by moving the nodes offscreen and checking if the panning is working as expected.
If you want to check what's causing the rendering issue you could try eliminating potential issues one by one. (e.g. the icons, the port inputs, the DropsShadowEffect's you have some).
I also recommend trying rendering a few hundred nodes in the playground application and comparing the offscreen and onscreen performance.
There's one rendering optimization that is applied when zooming out to 70% (see NodifyEditor.OptimizeRenderingZoomOutPercent
) and having at least 700 nodes present in the editor (see NodifyEditor.OptimizeRenderingMinimumContainers
). The nodes will be rendered to a bitmap in this case.
I have around 800 nodes in this video and it's still working smoothly. As you can see, the lag increases with the number of nodes present on the screen (by zooming out) until it reaches the rendering optimization threshold and it converts everything to a bitmap.
If rendering a node is expensive, try caching the result to a bitmap. Make sure you render the bitmap at the editor's maximum scale (2.0 by default) to avoid blurry results.
Note that I applied this to the
ItemContainer
itself but you can apply it to individual nodes if that works better in your case.
<nodify:NodifyEditor.ItemContainerStyle>
<Style TargetType="{x:Type nodify:ItemContainer}"
BasedOn="{StaticResource {x:Type nodify:ItemContainer}}">
<Setter Property="CacheMode">
<Setter.Value>
<BitmapCache RenderAtScale="2" />
</Setter.Value>
</Setter>
</Style>
</nodify:NodifyEditor.ItemContainerStyle>
There are 1000 nodes in this video and the performance improved a lot by caching the ItemContainer
s to a bitmap.
I hope this helps!
This ended up being a performance issue with a theme package we were using. Specifically the styling it was using for the textbox.
Thanks for all your help!
Hi,
Having some issues with lag when adding a large amount of nodes (10+)
https://user-images.githubusercontent.com/44004215/232871680-7049afc5-7c36-4a78-9bc3-181622519452.mp4
Only present with nodes that have UI elements in the port (textbox, combobox, etc.). With or without bindings. It appears to only effect the camera panning which you can see in the attached video. The rest of the UI is lag free.
Version 1.7