Merge pull request #372 from GICodeWarrior/patch-1

Improve TreeView and Export performance
This commit is contained in:
Valentin 2023-03-18 22:34:49 +01:00 committed by GitHub
commit 928834fd4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 33 deletions

View File

@ -4,6 +4,8 @@
xmlns:local="clr-namespace:FModel"
xmlns:controls="clr-namespace:FModel.Views.Resources.Controls"
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
xmlns:settings="clr-namespace:FModel.Settings"
xmlns:services="clr-namespace:FModel.Services"
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI"
xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI"
@ -95,7 +97,7 @@
</MenuItem>
<Separator />
<MenuItem Header="Auto Open Sounds" IsCheckable="True" StaysOpenOnClick="True"
IsChecked="{Binding IsAutoOpenSounds, Source={x:Static local:Settings.UserSettings.Default}}" />
IsChecked="{Binding IsAutoOpenSounds, Source={x:Static settings:UserSettings.Default}}" />
</MenuItem>
<MenuItem Header="Views">
<MenuItem Header="3D Viewer" Command="{Binding MenuCommand}" CommandParameter="Views_3dViewer">
@ -221,7 +223,7 @@
<TextBlock Grid.Row="0" Grid.Column="0" Text="Loading Mode" VerticalAlignment="Center" />
<ComboBox Grid.Row="0" Grid.Column="2" ItemsSource="{Binding LoadingModes.Modes}" IsEnabled="{Binding Status.IsReady}"
SelectedItem="{Binding LoadingMode, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}">
SelectedItem="{Binding LoadingMode, Source={x:Static settings:UserSettings.Default}, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={x:Static converters:EnumToStringConverter.Instance}}" />
@ -327,7 +329,7 @@
</StackPanel>
</Grid>
<Separator Grid.Row="1" Style="{StaticResource CustomSeparator}" Margin="0" />
<TreeView Grid.Row="2" x:Name="AssetsFolderName" Style="{StaticResource AssetsFolderTreeView}" PreviewMouseDoubleClick="OnAssetsTreeMouseDoubleClick">
<TreeView Grid.Row="2" x:Name="AssetsFolderName" Style="{StaticResource AssetsFolderTreeView}" PreviewMouseDoubleClick="OnAssetsTreeMouseDoubleClick" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" ScrollViewer.CanContentScroll="True">
<TreeView.ContextMenu>
<ContextMenu>
<MenuItem Header="Extract Folder's Packages" Click="OnFolderExtractClick">
@ -671,7 +673,7 @@
<TabControl Grid.Row="0" x:Name="TabControlName" Style="{StaticResource GameFilesTabControl}" />
<Expander Grid.Row="1" Margin="0 5 0 5" ExpandDirection="Down"
IsExpanded="{Binding IsLoggerExpanded, Source={x:Static local:Settings.UserSettings.Default}}">
IsExpanded="{Binding IsLoggerExpanded, Source={x:Static settings:UserSettings.Default}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
@ -734,7 +736,7 @@
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.ErrorBrush}}" />
<Setter Property="Foreground" Value="White" />
</DataTrigger>
<DataTrigger Binding="{Binding StatusChangeAttempted, Source={x:Static local:Services.ApplicationService.ThreadWorkerView}}" Value="True">
<DataTrigger Binding="{Binding StatusChangeAttempted, Source={x:Static services:ApplicationService.ThreadWorkerView}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard Duration="0:0:0.8">
@ -751,7 +753,7 @@
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding OperationCancelled, Source={x:Static local:Services.ApplicationService.ThreadWorkerView}}" Value="True">
<DataTrigger Binding="{Binding OperationCancelled, Source={x:Static services:ApplicationService.ThreadWorkerView}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard Duration="0:0:1">
@ -780,7 +782,7 @@
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding CanBeCanceled, Source={x:Static local:Services.ApplicationService.ThreadWorkerView}}" Value="True" />
<Condition Binding="{Binding CanBeCanceled, Source={x:Static services:ApplicationService.ThreadWorkerView}}" Value="True" />
<Condition Binding="{Binding Status.Kind}" Value="{x:Static local:EStatusKind.Loading}" />
</MultiDataTrigger.Conditions>
<Setter Property="Text" Value="{Binding Status.Label, StringFormat='{}{0} … ESC to Cancel'}" />
@ -805,7 +807,7 @@
<StatusBarItem.Style>
<Style TargetType="StatusBarItem">
<Style.Triggers>
<DataTrigger Binding="{Binding IsAutoOpenSounds, Source={x:Static local:Settings.UserSettings.Default}}" Value="False">
<DataTrigger Binding="{Binding IsAutoOpenSounds, Source={x:Static settings:UserSettings.Default}}" Value="False">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>

View File

@ -507,7 +507,7 @@ public class CUE4ParseViewModel : ViewModel
{
foreach (var asset in assetItems)
{
Thread.Sleep(10);
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
Extract(cancellationToken, asset.FullPath, TabControl.HasNoTabs);
}
@ -517,7 +517,7 @@ public class CUE4ParseViewModel : ViewModel
{
foreach (var asset in folder.AssetsList.Assets)
{
Thread.Sleep(10);
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
try
{

View File

@ -1,4 +1,5 @@
using System.Diagnostics;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using AdonisUI.Controls;
using FModel.Extensions;
@ -79,19 +80,13 @@ public class MenuCommand : ViewModelCommand<ApplicationViewModel>
case "ToolBox_Expand_All":
await ApplicationService.ThreadWorkerView.Begin(cancellationToken =>
{
foreach (var folder in contextViewModel.CUE4Parse.AssetsFolder.Folders)
{
LoopFolders(cancellationToken, folder, true);
}
SetFoldersIsExpanded(contextViewModel.CUE4Parse.AssetsFolder, true, cancellationToken);
});
break;
case "ToolBox_Collapse_All":
await ApplicationService.ThreadWorkerView.Begin(cancellationToken =>
{
foreach (var folder in contextViewModel.CUE4Parse.AssetsFolder.Folders)
{
LoopFolders(cancellationToken, folder, false);
}
SetFoldersIsExpanded(contextViewModel.CUE4Parse.AssetsFolder, false, cancellationToken);
});
break;
case TreeItem selectedFolder:
@ -101,15 +96,44 @@ public class MenuCommand : ViewModelCommand<ApplicationViewModel>
}
}
private void LoopFolders(CancellationToken cancellationToken, TreeItem parent, bool isExpanded)
private static void SetFoldersIsExpanded(AssetsFolderViewModel root, bool isExpanded, CancellationToken cancellationToken)
{
if (parent.IsExpanded != isExpanded)
LinkedList<TreeItem> nodes = new();
foreach (TreeItem folder in root.Folders)
{
parent.IsExpanded = isExpanded;
Thread.Sleep(10);
nodes.AddLast(folder);
}
cancellationToken.ThrowIfCancellationRequested();
foreach (var f in parent.Folders) LoopFolders(cancellationToken, f, isExpanded);
LinkedListNode<TreeItem> current = nodes.First;
while (current != null)
{
TreeItem folder = current.Value;
// Collapse top-down (reduce layout updates)
if (!isExpanded)
{
folder.IsExpanded = isExpanded;
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
}
foreach (TreeItem child in folder.Folders)
{
nodes.AddLast(child);
}
current = current.Next;
}
// Expand bottom-up (reduce layout updates)
if (isExpanded)
{
for (LinkedListNode<TreeItem> node = nodes.Last; node != null; node = node.Previous)
{
node.Value.IsExpanded = isExpanded;
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
}
}
}
}

View File

@ -6,6 +6,7 @@
xmlns:soundOut="clr-namespace:CSCore.SoundOut;assembly=CSCore"
xmlns:audioControls="clr-namespace:FModel.Views.Resources.Controls.Aup"
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
xmlns:settings="clr-namespace:FModel.Settings"
xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit"
xmlns:folding="clr-namespace:ICSharpCode.AvalonEdit.Folding;assembly=ICSharpCode.AvalonEdit"
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
@ -182,19 +183,19 @@
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding LoadingMode, Source={x:Static local:Settings.UserSettings.Default}}" Value="{x:Static local:ELoadingMode.Single}">
<DataTrigger Binding="{Binding LoadingMode, Source={x:Static settings:UserSettings.Default}}" Value="{x:Static local:ELoadingMode.Single}">
<Setter Property="SelectionMode" Value="Single" />
</DataTrigger>
<DataTrigger Binding="{Binding LoadingMode, Source={x:Static local:Settings.UserSettings.Default}}" Value="{x:Static local:ELoadingMode.Multiple}">
<DataTrigger Binding="{Binding LoadingMode, Source={x:Static settings:UserSettings.Default}}" Value="{x:Static local:ELoadingMode.Multiple}">
<Setter Property="SelectionMode" Value="Extended" />
</DataTrigger>
<DataTrigger Binding="{Binding LoadingMode, Source={x:Static local:Settings.UserSettings.Default}}" Value="{x:Static local:ELoadingMode.All}">
<DataTrigger Binding="{Binding LoadingMode, Source={x:Static settings:UserSettings.Default}}" Value="{x:Static local:ELoadingMode.All}">
<Setter Property="SelectionMode" Value="Extended" />
</DataTrigger>
<DataTrigger Binding="{Binding LoadingMode, Source={x:Static local:Settings.UserSettings.Default}}" Value="{x:Static local:ELoadingMode.AllButNew}">
<DataTrigger Binding="{Binding LoadingMode, Source={x:Static settings:UserSettings.Default}}" Value="{x:Static local:ELoadingMode.AllButNew}">
<Setter Property="SelectionMode" Value="Extended" />
</DataTrigger>
<DataTrigger Binding="{Binding LoadingMode, Source={x:Static local:Settings.UserSettings.Default}}" Value="{x:Static local:ELoadingMode.AllButModified}">
<DataTrigger Binding="{Binding LoadingMode, Source={x:Static settings:UserSettings.Default}}" Value="{x:Static local:ELoadingMode.AllButModified}">
<Setter Property="SelectionMode" Value="Extended" />
</DataTrigger>
</Style.Triggers>
@ -247,7 +248,7 @@
</Style>
<Style x:Key="AssetsFolderTreeView" TargetType="TreeView" BasedOn="{StaticResource {x:Type TreeView}}">
<Setter Property="ItemsSource" Value="{Binding CUE4Parse.AssetsFolder.FoldersView, IsAsync=True}" />
<Setter Property="ItemsSource" Value="{Binding CUE4Parse.AssetsFolder.FoldersView}" />
<Setter Property="adonisExtensions:ScrollViewerExtension.VerticalScrollBarExpansionMode" Value="NeverExpand"/>
<Setter Property="adonisExtensions:ScrollViewerExtension.VerticalScrollBarPlacement" Value="Docked"/>
<Setter Property="adonisExtensions:ScrollViewerExtension.HorizontalScrollBarExpansionMode" Value="NeverExpand"/>
@ -255,7 +256,7 @@
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="ItemTemplate">
<Setter.Value>
<HierarchicalDataTemplate ItemsSource="{Binding FoldersView, IsAsync=True}">
<HierarchicalDataTemplate ItemsSource="{Binding FoldersView}">
<StackPanel Orientation="Horizontal">
<Image x:Name="TreeImage" Source="/FModel;component/Resources/folder.png"
Width="16" Height="16" HorizontalAlignment="Center" Margin="0 0 3.5 0" />
@ -647,7 +648,7 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="{Binding AvalonImageSize, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<ColumnDefinition Width="{Binding AvalonImageSize, Source={x:Static settings:UserSettings.Default}, Mode=TwoWay}" />
</Grid.ColumnDefinitions>
<controls:AvalonEditor x:Name="DynamicArea" Grid.Column="0" DataContext="{Binding SelectedItem, ElementName=TabControlName}" />