質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

1回答

266閲覧

C# WPFのWindowのフリーズについて(Dispatcher)

halotora

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

0クリップ

投稿2024/10/09 17:07

C# WPFで非同期処理中のWindowのフリーズについて質問があります。

public MainWindow() { InitializeComponent(); } private async void Window_Loaded(object sender, RoutedEventArgs e) { await Task.Run(() => { Dispatcher.InvokeAsync(new Action(() => { TreeViewItem TreeViewItem = new TreeViewItem(); System.Threading.Thread.Sleep(10000);//重い処理 })); }); }

Window_Load中に上記コードを入れるとWindowがフリーズして動かなくなってしまいます。
Thread.Sleepの部分はTreeViewItemに大量のDataを入れる関数がありましたが、
Windowがフリーズして動かなくなってしまったので、
Dispatcher.InvokeをDispatcher.InvokeAsyncに変えて対応してみましたが、結果が同じでした。

非同期中にTreeViewItemを大量に扱う場合はどのように対処すれば良いでしょうか?
よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

Thread.Sleepの部分はTreeViewItemに大量のDataを入れる関数がありました

TreeViewItemをひとつ作るのに時間がかかるということでしょうか?

Dispatcher.InvokeをDispatcher.InvokeAsyncに変えて対応してみましたが、結果が同じでした。

InvokeAsync中で重い処理があったら、結局当初のコードと同じことになります。
重い部分(だけ)を、別スレッドに回してください。

cs

1using System.Windows; 2using System.Windows.Controls; 3 4namespace Qrub8esahzjqmu3; 5 6public partial class MainWindow : Window 7{ 8 public MainWindow() => InitializeComponent(); 9 10 private async void Window_Loaded(object sender, RoutedEventArgs e) 11 { 12 for (var i = 1; i < 100; i++) 13 { 14 //var header = GetData(i); // こうだとフリーズ 15 var header = await Task.Run(() => GetData(i)); 16 treeView.Items.Add(new TreeViewItem { Header = header, }); 17 } 18 } 19 20 private string GetData(int i) 21 { 22 Thread.Sleep(100); // 何か時間がかかるとして 23 return $"Item{i}"; 24 } 25}

TreeViewItemを大量に扱う場合はどのように対処すれば良いでしょうか?

それとも「TreeViewItemを10,000個追加している」ような話でしょうか?

その場合は、TreeViewを仮想化するとかなり改善すると思います。
方法: TreeView のパフォーマンスを改善する - WPF .NET Framework | Microsoft Learn

xml

1<Window 2 x:Class="Qrub8esahzjqmu3.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 Width="800" 6 Height="450" 7 Loaded="Window_Loaded"> 8 <Grid> 9 <TreeView x:Name="treeView" VirtualizingStackPanel.IsVirtualizing="True" /> 10 </Grid> 11</Window>

cs

1using System.Windows; 2 3namespace Qrub8esahzjqmu3; 4 5public partial class MainWindow : Window 6{ 7 public MainWindow() => InitializeComponent(); 8 9 private void Window_Loaded(object sender, RoutedEventArgs e) 10 { 11 for (var i = 1; i < 10_000; i++) 12 { 13 treeView.Items.Add($"Item{i}"); 14 } 15 } 16}

のコードでは、やはり中でWPFのコントロールに触れなければならず、

さらに子ノードを追加しているとかですかね?

ThemeModeの確認がてらバインドでの例

xml

1<Window 2 x:Class="Qrub8esahzjqmu3.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:local="clr-namespace:Qrub8esahzjqmu3" 6 Width="800" 7 Height="450" 8 Loaded="Window_Loaded"> 9 <Grid> 10 <TreeView x:Name="treeView"> 11 <TreeView.ItemTemplate> 12 <HierarchicalDataTemplate DataType="local:Node" ItemsSource="{Binding Children}"> 13 <TextBlock Text="{Binding Name}" /> 14 </HierarchicalDataTemplate> 15 </TreeView.ItemTemplate> 16 </TreeView> 17 </Grid> 18</Window>

cs

1using System.Collections.ObjectModel; 2using System.Windows; 3 4namespace Qrub8esahzjqmu3; 5 6public partial class MainWindow : Window 7{ 8 public MainWindow() 9 { 10 InitializeComponent(); 11 12#pragma warning disable WPF0001 // 種類は、評価の目的でのみ提供されています。将来の更新で変更または削除されることがあります。続行するには、この診断を非表示にします。 13 Application.Current.ThemeMode = ThemeMode.Dark; 14 } 15 16 private async void Window_Loaded(object sender, RoutedEventArgs e) 17 { 18 treeView.ItemsSource = await Task.Run(() => 19 { 20 var root = new Node(); 21 Add(root, 10, "Node"); 22 return root.Children; 23 }); 24 25 static Node Add(Node node, int c, string name) 26 { 27 for (var i = 1; i <= c; i++) 28 { 29 var n = new Node() { Name = $"{name}-{i}", }; 30 Add(n, c - 1, n.Name); 31 node.Children.Add(n); 32 } 33 return node; 34 } 35 } 36} 37 38public class Node 39{ 40 public string? Name { get; set; } 41 public ObservableCollection<Node> Children { get; } = []; 42}

アプリ動画

投稿2024/10/09 21:29

編集2024/10/11 10:52
TN8001

総合スコア9813

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

halotora

2024/10/10 10:26 編集

回答ありがとうございました。 上記の await Task.Run(() => GetData(i)); のコードでは、やはり中でWPFのコントロールに触れなければならず、 Dispatcher無しで起こるエラー 「呼び出しスレッドは、多数の UI コンポーネントが必要としているため、STA である必要があります。」 になり例外となってしまいました。 TreeViewコントロールではなく、別のコントロールにしたところ エラーが無くなり解決できました。
TN8001

2024/10/10 10:33

> のコードでは、やはり中でWPFのコントロールに触れなければならず、 さらに子ノードを追加しているとかですかね? > になり例外となってしまいました。 そうなりますね。 具体的なコードがあれば何か回避法もあるとは思いますが... 「仮想化」だけでは大して改善しませんでしたか? > WPFのTreeViewコントロールではなく、Windows.Formにしたところ > エラーが無くなり解決できました。 あっそうですか^^; halotoraさんがそれでよければかまいません。 質問を「解決済」にしてください(自己解決でも結構です) [ヘルプ|質問を解決済みにしたい](https://teratail.com/help#resolve-question) [ヘルプ|質問をした後に自己解決してしまった](https://teratail.com/help#resolve-myself)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問