実現したいこと・分からないこと
- wpfで、重い処理の進捗をUI(View)に逐次反映させたいですが、反映できません。
- MVVMでコマンドから起動する処理が発行するメッセージを、処理が終わってから一度に表示するのではなく、都度Viewに反映させたいです。
- 非同期(
Task
)は使ったことがなかったので、あまり理解できてないかもしれません。 - 逐次反映させる方法が知りたいです。
よろしくお願いいたします。
VB
1 ' ViewModel 2 Private _MyCommand As ICommand 3 Public ReadOnly Property MyCommand As ICommand 4 Get 5 If Me._MyCommand Is Nothing Then 6 Me._MyCommand = New DelegateCommand With { 7 .ExecuteHandler = AddressOf _MyCommandExecute, 8 .CanExecuteHandler = AddressOf _MyCommandCanExecute 9 } 10 End If 11 Return Me._MyCommand 12 End Get 13 End Property 14 Private Sub MyCommandExecute(ByVal para As Object) 15 Threading.Thread.Sleep(1000) 16 Me.Output = "hoge" ' 進捗1 17 Threading.Thread.Sleep(1000) 18 Me.Output &= "fuga" ' 進捗2 19 End Sub 20 Private Function MyCommandCanExecute(ByVal para As Object) As Boolean 21 Return True 22 End Function
xaml
1 <!-- View --> 2 <Grid> 3 <Menu> 4 <MenuItem Icon="{Binding Icon}" Command="{Binding MyCommand}" /> 5 </Menu> 6 <TextBlock Text="{Binding Output}" /> 7 </Grid>
やってみたこと
ViewのIsAsyncプロパティにTrueを指定
xaml
1 <!-- View --> 2 <Grid> 3 <Menu> 4 <MenuItem Icon="{Binding Icon}" Command="{Binding MyCommand}" /> 5 </Menu> 6 <TextBlock Text="{Binding Output, IsAsync=True}" /> 7 </Grid>
- バインディングソースにセットするメソッドをわざわざ非同期にしなくとも、ターゲット側を非同期に反映できればいいのかと思ったが、msdnの
IsAsync
に関する資料を見たら、どうやら読み書きに時間が掛かる場合に、一旦パスができるという、こちらの期待と違う感じ。
非同期処理(?)にセットさせてみる
VB
1 Private Async Sub MyCommandExecute(ByVal para As Object) 2 Dim t As Task(Of String) = Task.Run( 3 Function() 4 Me.Output &= "hoge" 5 Return "hoge" 6 End Function 7 ) 8 Await t 9 Threading.Thread.Sleep(1000) 10 Me.Output &= t.Result 11 12 Threading.Thread.Sleep(1000) 13 Dim t2 As Task(Of String) = Task.Run( 14 Function() 15 Me.Output &= "fuga" 16 Return "fuga" 17 End Function 18 ) 19 Await t2 20 Me.Output &= t2.Result 21 End Sub
- そもそも、これで非同期処理が書けているのかが疑問。また参考にしたサイトによると、「UIスレッド以外でセットさせると例外が発生する」とのことだが、発生しないのが謎(コマンドからの起動がおかしい?)
一応、別スレッド側で値を返して、本スレッドでセットさせるロジックも書いてみたが、やはりセットされない。
(そもそも本スレッドでセットしたら、非同期にならないんじゃないかとも思う)
追記
考えが逆だったかも・・・
下のように書いたら、逐次反映できてた
Private Async Sub MyCommandExecute(ByVal para As Object) Dim t As Task(Of String) = Task.Run( Function() Threading.Thread.Sleep(1000) End Function ) Await t Me.Output &= "hoge" Threading.Thread.Sleep(1000) Dim t2 As Task(Of String) = Task.Run( Function() Threading.Thread.Sleep(1000) End Function ) Await t2 Me.Output &= "fuga" End Sub
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2021/02/09 04:41