gpt4 book ai didi

c# - [C#][WPF]如何在不卡住UI的情况下制作异步TreeView?

转载 作者:行者123 更新时间:2023-11-30 15:49:43 25 4
gpt4 key购买 nike

我想制作一个显示服务器和文件夹的 TreeView。根据我的需要,我制作了 2 个类:

-- 文件夹

class Folder
{
// Hidden attributes
public String ElementID { get; set; }

// Attributes displayed in the treeview
public String ElementName { get; set; }

// This collection is binded with the GUI defined in XAML
public CompositeCollection Children { get; set; }

public BitmapImage Image {get; set; }

// Constructor
public Folder()
{
// Fill the treeview with a temporary child as text
Children = new CompositeCollection();
Children.Add(new TextBlock()
{
Text = "Loading...",
FontStyle = FontStyles.Italic
});
}

// Fill the Children collection
public void LoadChildren()
{
// Clear the Children list
Children.Clear();

// Populate the treeview thanks to the bind
foreach (Folder folder in this.GetChildren())
{
Children.Add(folder);
}
}

// Get the Folder Children as Folder
protected List<Folder> GetChildren()
{
System.Threading.Thread.Sleep(1000);

List<Folder> resu = new List<Folder>();

Folder f1 = new Folder();
f1.ElementID = "1";
f1.ElementName = "folder 1";

Folder f2 = new Folder();
f2.ElementID = "2";
f2.ElementName = "folder 2";

Folder f3 = new Folder();
f3.ElementID = "3";
f3.ElementName = "folder 3";

Folder f4 = new Folder();
f4.ElementID = "4";
f4.ElementName = "folder 4";

resu.Add(f1);
resu.Add(f2);
resu.Add(f3);
resu.Add(f4);

return resu;
}

Thread.Sleep() 模拟该方法可能需要一段时间。

-- 服务器:文件夹

 class Server : Folder
{
// Get the Servers list
public static List<Server> GetServers()
{
System.Threading.Thread.Sleep(1500);

// Create a list of Servers
List<Server> servers = new List<Server>();

Server s1 = new Server();
s1.ElementID = "1";
s1.ElementName = "Server 1";

Server s2 = new Server();
s2.ElementID = "2";
s2.ElementName = "Server 2";

Server s3 = new Server();
s3.ElementID = "3";
s3.ElementName = "Server 3";

Server s4 = new Server();
s4.ElementID = "4";
s4.ElementName = "Server 4";

servers.Add(s1);
servers.Add(s2);
servers.Add(s3);
servers.Add(s4);

return servers;
}
}

这是我的 TreeView 代码:

XAML 部分:

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ar="clr-namespace:WpfApplication1"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="Browser" Height="327" Width="250">
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type ar:Folder}" ItemsSource="{Binding Path=Children}" >
<StackPanel Orientation="Horizontal">
<Image Source="Images\TreeView\folder.png" Height="15" Width="15" />
<TextBlock Text="{Binding Path=ElementName}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type ar:Server}" ItemsSource="{Binding Path=Children}">
<StackPanel Orientation="Horizontal">
<Image Source="Images\TreeView\server.png" Height="15" Width="15" />
<TextBlock Text="{Binding Path=ElementName}" />
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<TreeView HorizontalAlignment="Stretch" Width="230" Name="treeView">
<TreeViewItem Header="Servers" x:Name="root" x:FieldModifier="private">
<TreeViewItem TextBlock.FontStyle="Italic"
Header="Loading..."/>
</TreeViewItem>
</TreeView>
</Grid>

代码隐藏:

public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();

// Add an event in order to know when an TreeViewItem is Expanded
AddHandler(TreeViewItem.ExpandedEvent, new RoutedEventHandler(treeItemExpanded), true);
}

// Event when a treeitem expands
private void treeItemExpanded(object sender, RoutedEventArgs e)
{
// Get the source
var item = e.OriginalSource as TreeViewItem;

// If the item source is a Simple TreeViewItem
if (item == null)
return;

if (item.Name == "root")
{
List<Server> servers = new List<Server>();

servers = Server.GetServers();

root.Items.Clear();

// Fill the treeview with the servers
root.ItemsSource = servers;
}

// Get data from item as Folder (also works for Server)
var treeViewElement = item.DataContext as Folder;

// If there is no data
if (treeViewElement == null)
return;

// Load Children ( populate the treeview )
ThreadPool.QueueUserWorkItem(delegate
{
Dispatcher.BeginInvoke(DispatcherPriority.Background, (ThreadStart)delegate
{
treeViewElement.LoadChildren();

});
});
}
}

我想让 UI 在扩展 treeView 项目时不卡住(2 种情况:根目录扩展,文件夹扩展)

暂时1- 当我扩展根节点时,我没有看到“正在加载...”我试过这样的事情,但有一个异常(exception):线程必须处于 STA 模式:

// Load Children ( populate the treeview )
ThreadPool.QueueUserWorkItem(delegate
{
List<Server> servers = Server.GetServers();

Dispatcher.BeginInvoke(DispatcherPriority.Background, (ThreadStart)delegate
{
root.Items.Clear();

// Fill the treeview with the servers
root.ItemsSource = servers;
});
});

2- 当一个节点被扩展时,我有“正在加载...”,过了一会儿,UI 被更新了。在此期间,UI 被卡住:用户无法移动窗口。

你能帮帮我吗?

(PS:如果您有任何其他意见,我很乐意在这里提出;))

最佳答案

谢谢加里,但我找到了另一个几乎可以解决所有问题的解决方案:)

首先,我添加一个空类 CustomTreeViewITem

class CustomTreeViewItem
{ }

此类在 XAML 中使用。

我在文件夹类中更改了一些内容: - 将 CompositeCollection 替换为 ObservableCollection - 使文件夹继承自 CustomTreeViewItem - 改变构造函数

class Folder : CustomTreeViewItem
{
// Hidden attributes
public String ElementID { get; set; }

// Attributes displayed in the treeview
public String ElementName { get; set; }

public ObservableCollection<CustomTreeViewItem> Children { get; set; } // This collection is binded with the GUI defined in XAML

// Constructor
public Folder()
{
// Fill the treeview with a temporary child as text
Children = new ObservableCollection<CustomTreeViewItem>();
Children.Add(new CustomTreeViewItem());
}

// Get the Folder Children as Folder
// Method overriden by the Server class
public List<Folder> GetChildren()
{
System.Threading.Thread.Sleep(5000);

List<Folder> resu = new List<Folder>();

Folder f1 = new Folder();
f1.ElementID = "1";
f1.ElementName = "folder 1";

Folder f2 = new Folder();
f2.ElementID = "2";
f2.ElementName = "folder 2";

Folder f3 = new Folder();
f3.ElementID = "3";
f3.ElementName = "folder 3";

Folder f4 = new Folder();
f4.ElementID = "4";
f4.ElementName = "folder 4";

resu.Add(f1);
resu.Add(f2);
resu.Add(f3);
resu.Add(f4);

return resu;
}

我没有更改服务器类

现在我的 XAML 看起来像这样:

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ar="clr-namespace:WpfApplication1"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="Browser" Height="327" Width="250">
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type ar:Folder}" ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=ElementName}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type ar:Server}" ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=ElementName}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type ar:CustomTreeViewItem}">
<TextBlock Text="Loading..." />
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<TreeView HorizontalAlignment="Stretch" Width="230" Name="treeView">
<TreeViewItem Header="Servers" x:Name="root" x:FieldModifier="private">
<ar:CustomTreeViewItem/>
</TreeViewItem>
</TreeView>
</Grid>

还有我的代码:

private void treeItemExpanded(object sender, RoutedEventArgs e)
{
// Get the source
var item = e.OriginalSource as TreeViewItem;

// If the item source is a Simple TreeViewItem
if (item == null)
// then Nothing
{ return; }

if (item.Name == "root")
{
// Load Children ( populate the treeview )
ThreadPool.QueueUserWorkItem(delegate
{
List<Server> servers = Server.GetServers();

Dispatcher.BeginInvoke(DispatcherPriority.Background, (ThreadStart)delegate
{
root.Items.Clear();

// Fill the treeview with the servers
root.ItemsSource = servers;
});
});
}

// Get data from item as Folder (also works for Server)
Folder treeViewElement = item.DataContext as Folder;

// If there is no data
if (treeViewElement == null)
{
return;
}
// Load Children ( populate the treeview )
ThreadPool.QueueUserWorkItem(delegate
{

// Clear the Children list
var children = treeViewElement.GetChildren();

// Populate the treeview thanks to the bind

Dispatcher.BeginInvoke(DispatcherPriority.Background, (ThreadStart)delegate
{
treeViewElement.Children.Clear();

foreach (Folder folder in children)
{
treeViewElement.Children.Add(folder);
}

});
});
}

它使我能够自定义每个 TreeViewClass(自定义、文件夹、服务器),感谢 HierarchicalDataTemplate。

关于c# - [C#][WPF]如何在不卡住UI的情况下制作异步TreeView?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1221180/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com