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

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

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

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

WPF

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

Q&A

解決済

2回答

3302閲覧

[WPF]別スレッドからコンボボックスの内容を更新して選択項目を再設定する方法について

Lewis1111

総合スコア12

C#

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

WPF

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

0グッド

0クリップ

投稿2022/01/09 04:37

前提・実現したいこと

WPF、C#、Prism、ReactiveProperty

別スレッドで処理を流しておき変更があった場合、変更を通知してCombboxを更新するようにしたい。
選択済みの場合リスト更新後も選択した項目が残っていた場合、再選択するようにしたい。

試したこと

C#

1public class ContentGridViewModel : BindableBase, INavigationAware 2{ 3 public ObservableCollection<SampleInfo> SampleInfos { get; } 4 public ReactivePropertySlim<SampleInfo> SelectedInfo { get; } 5 6 public ContentGridViewModel(IContentGridService contentGridService, IRegionManager regionManager) 7 { 8  SampleInfos = new ObservableCollection<SampleInfo>(); 9  SelectedInfo = new ReactivePropertySlim<SampleInfo>(); 10 11  BindingOperations.EnableCollectionSynchronization(SampleInfos, new object()); 12 13  SampleInfos.AddRange(別クラスに保持しているリストを設定); 14 15  // コンボボックス選択時イベント 16  SelectedInfo.Subscribe(o => 17 { 18  foreach (var info in SampleInfos) 19 { 20  info.IsSelected = info?.TestNumber == o?.TestNumber; 21 } 22 }).AddTo(Disposable); 23 } 24 25 public async void OnNavigatedTo(NavigationContext navigationContext) 26 { 27  // 接続情報取得後Subject 28 SampleService.InfoSubject = new Subject<bool>(); 29 SampleService.InfoSubject.Subscribe(o => ReceiveInfo()); 30 } 31 32 // 別スレッドで変更を監視して変更があった場合、Subjectを使って変更を通知してReceiveInfo関数を呼ぶ。 33 private void ReceiveInfo() 34 { 35  var selectedInfo = SelectedInfo.Value; 36 37 // コンボボックスリストの内容更新処理 38 SampleInfoListUpdate(別クラスに保持しているリストを設定); 39 40  // コンボボックス再選択 41 var tmp = SampleInfos.Where(o => o.TestNumber == selectedInfo.TestNumber).ToList(); 42  SelectedInfo.Value = tmp.FirstOrDefault(); 43 } 44 45 // コンボボックスリストの内容更新処理 46 private void SampleInfoListUpdate(List<SampleInfo> list) 47 { 48 SampleInfos.Clear(); 49  foreach (var info in list) 50 { 51  SampleInfos.Add(info); 52 } 53 } 54}

xaml

1<ComboBox Grid.Row="1" 2 ItemsSource="{Binding SampleInfos}" 3 SelectedItem="{Binding Path=SelectedInfo.Value}" 4 DisplayMemberPath="TestNumber" />

コンボボックスの内容は更新されているが、選択項目の再設定が出来ない。
試しに未選択の状態でReceiveInfoを動かしリストの先頭を選択するようにすると先頭の項目が選択状態になるが、
選択済みにしてReceiveInfoを動かし先頭項目を選択済みにすると未選択状態になる。
別スレッドからの更新の場合、SelectedItemに設定する場合何かしないといけないのでしょうか?
解決方法を教えて頂けたら幸いです。

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

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

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

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

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

guest

回答2

0

理由はさっぱりわかりませんが、SampleInfos更新する前SelectedInfonullにしておくと動作するようになりました。

確認した簡略コード

xml

1<Window 2 x:Class="Questions377285.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:Questions377285" 6 Width="800" 7 Height="450"> 8 <Window.DataContext> 9 <local:ContentGridViewModel /> 10 </Window.DataContext> 11 <Grid> 12 <Grid.RowDefinitions> 13 <RowDefinition Height="Auto" /> 14 <RowDefinition Height="Auto" /> 15 <RowDefinition /> 16 </Grid.RowDefinitions> 17 <Button Command="{Binding Command}" Content="UIスレッド Update" /> 18 <ComboBox 19 Grid.Row="1" 20 DisplayMemberPath="TestNumber" 21 ItemsSource="{Binding SampleInfos}" 22 SelectedItem="{Binding SelectedInfo.Value}" /> 23 <ListBox 24 Grid.Row="2" 25 DisplayMemberPath="TestNumber" 26 ItemsSource="{Binding SampleInfos}" 27 SelectedItem="{Binding SelectedInfo.Value}" /> 28 </Grid> 29</Window>

cs

1using System; 2using System.Collections.Generic; 3using System.Collections.ObjectModel; 4using System.Linq; 5using System.Reactive.Subjects; 6using System.Threading.Tasks; 7using System.Windows; 8using System.Windows.Data; 9using Reactive.Bindings; 10 11namespace Questions377285 12{ 13 public class SampleInfo 14 { 15 public int TestNumber { get; set; } 16 public bool IsSelected { get; set; } 17 } 18 19 public class ContentGridViewModel 20 { 21 public ObservableCollection<SampleInfo> SampleInfos { get; } = new() 22 { 23 new() { TestNumber = 1, }, 24 new() { TestNumber = 2, }, 25 new() { TestNumber = 3, }, 26 }; 27 public ReactivePropertySlim<SampleInfo?> SelectedInfo { get; } = new(); 28 public ReactiveCommand Command { get; } = new(); 29 30 private readonly Subject<bool> InfoSubject = new(); 31 32 public ContentGridViewModel() 33 { 34 BindingOperations.EnableCollectionSynchronization(SampleInfos, new()); 35 36 SelectedInfo.Subscribe(o => 37 { 38 foreach (var info in SampleInfos) 39 { 40 info.IsSelected = info.TestNumber == o?.TestNumber; 41 } 42 }); 43 44 InfoSubject.Subscribe(o => ReceiveInfo()); 45 46 Command.Subscribe(ReceiveInfo); 47 48 _ = Task.Run(async () => 49 { 50 while (true) 51 { 52 await Task.Delay(TimeSpan.FromSeconds(5)); 53 InfoSubject.OnNext(true); 54 } 55 }); 56 } 57 58 private void ReceiveInfo() 59 { 60 var selectedInfo = SelectedInfo.Value; 61 // *********ココ 62 SelectedInfo.Value = null; 63 64 SampleInfoListUpdate(Get()); 65 66 SelectedInfo.Value = SampleInfos.FirstOrDefault(o => o.TestNumber == selectedInfo?.TestNumber); 67 } 68 69 private List<SampleInfo> Get() 70 => Enumerable.Range(1, SampleInfos.Count + 1) 71 .Select(x => new SampleInfo { TestNumber = x, }) 72 .ToList(); 73 74 private void SampleInfoListUpdate(List<SampleInfo> list) 75 { 76 SampleInfos.Clear(); 77 foreach (var info in list) 78 { 79 SampleInfos.Add(info); 80 } 81 } 82 } 83 84 public partial class MainWindow : Window 85 { 86 public MainWindow() => InitializeComponent(); 87 } 88}

投稿2022/01/09 10:11

編集2023/07/29 14:03
TN8001

総合スコア9246

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

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

0

ベストアンサー

GUIにかかわる設定は同一スレッド上でする必要があります

【C#】UIスレッド以外からUIのコントロールを操作する │ FPGA完全に理解した

投稿2022/01/09 05:14

y_waiwai

総合スコア87719

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

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

Lewis1111

2022/01/15 03:08

private Dispatcher _dispather = null; _dispather = Dispatcher.CurrentDispatcher; _dispather.Invoke((() => { // 処理 }), DispatcherPriority.Normal); で実現できました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問