結論:
引数のEventArgs の値を変更する必要がある場合は、Prismのイベント発火「prism:InvokeCommandAction」を利用する
引数のEventArgs の値を参照しかしない場合は、Reactiveのイベント発火「rpi:EventToReactiveCommand」を利用する
Prismは「xmlns:prism="http://prismlibrary.com/" 」
Reactiveは「xmlns:rpi="clr-namespace:Reactive.Bindings.Interactivity;assembly=ReactiveProperty.WPF"」
色々やった事:
TextBox に対してファイルをドロップさせファイルパスを表示する。
といういたってシンプルなものを作ろうとしたが、ReactiveProperty で作れない…なぜだ!
って事でとりあえず動かないソース:(一部抜粋)
MainPage.xaml:
MainPageViewModel:
何がダメか:
1.DoPreviewDragOver メソッドに処理が来るが、Handled と Effects に値を設定しても、反映されていないっぽい。
⇒ 結果、画面のマウスマークは禁止マークから変更されない。
2.上記より、DoDropFile メソッドが呼び出されない。
ちなみに「コードビハインド(*.xaml.cs) でイベントを記載した所、同じ処理でも正常に動作する」てな感じです。
で、悩むこと数日… たまたま Reactiveで有名(本家)な かずきさん のページをぼーっと眺めていると
ここ:https://blog.okazuki.jp/entry/2019/04/19/172010
Reactive でのイベント発火方法と、Prismのイベント発火方法が記載されているではないですか…
まさかね…と思いつつ下記を変更(XAML)
修正前:(Reactive で送信する方法)
修正後:(Prismで送る方法)
引数のEventArgs の値を変更する必要がある場合は、Prismのイベント発火「prism:InvokeCommandAction」を利用する
引数のEventArgs の値を参照しかしない場合は、Reactiveのイベント発火「rpi:EventToReactiveCommand」を利用する
Prismは「xmlns:prism="http://prismlibrary.com/" 」
Reactiveは「xmlns:rpi="clr-namespace:Reactive.Bindings.Interactivity;assembly=ReactiveProperty.WPF"」
色々やった事:
TextBox に対してファイルをドロップさせファイルパスを表示する。
といういたってシンプルなものを作ろうとしたが、ReactiveProperty で作れない…なぜだ!
って事でとりあえず動かないソース:(一部抜粋)
MainPage.xaml:
<UserControl なんかいろいろ xmlns:prism="http://prismlibrary.com/" xmlns:i="http://schemas.microsoft.com/xaml/behaviors" xmlns:rpi="clr-namespace:Reactive.Bindings.Interactivity;assembly=ReactiveProperty.WPF" prism:ViewModelLocator.AutoWireViewModel="True"> <Grid> <TextBox Text="{Binding FilePath.Value}" AllowDrop="True"> <i:Interaction.Triggers> <i:EventTrigger EventName="PreviewDragOver"> <rpi:EventToReactiveCommand Command="{Binding PreviewDragOver}" /> </i:EventTrigger> <i:EventTrigger EventName="PreviewDragLeave"> <rpi:EventToReactiveCommand Command="{Binding PreviewDragLeave}" /> </i:EventTrigger> <i:EventTrigger EventName="PreviewDrop"> <rpi:EventToReactiveCommand Command="{Binding PreviewDrop}" /> </i:EventTrigger> </i:Interaction.Triggers> </TextBox> </Grid> </UserControl>
MainPageViewModel:
public class MainPageViewModel : RegionViewModelBase, IDisposable, IDestructible { public ReactiveProperty<string> FilePath { get; set; } public ReactiveCommand<DragEventArgs> PreviewDragOver { get; set; } public ReactiveCommand<DragEventArgs> PreviewDragLeave { get; set; } public ReactiveCommand<DragEventArgs> PreviewDropFile { get; set; } public MainPageViewModel() { FilePath = new ReactiveProperty<string>(); PreviewDragOver = new ReactiveCommand<DragEventArgs>().WithSubscribe(DoPreviewDragOver); PreviewDragLeave = new ReactiveCommand<DragEventArgs>().WithSubscribe(DoPreviewDragLeave); PreviewDrop = new ReactiveCommand<DragEventArgs>().WithSubscribe(DoDropFile); } private void DoPreviewDragOver(DragEventArgs e) { e.Handled = true; e.Effects = DragDropEffects.Copy; } private void DoPreviewDragLeave(DragEventArgs e) { e.Effects = DragDropEffects.None; e.Handled = false; } private void DoDropFile(DragEventArgs e) { // ここに処理が来ない } }
何がダメか:
1.DoPreviewDragOver メソッドに処理が来るが、Handled と Effects に値を設定しても、反映されていないっぽい。
⇒ 結果、画面のマウスマークは禁止マークから変更されない。
2.上記より、DoDropFile メソッドが呼び出されない。
ちなみに「コードビハインド(*.xaml.cs) でイベントを記載した所、同じ処理でも正常に動作する」てな感じです。
で、悩むこと数日… たまたま Reactiveで有名(本家)な かずきさん のページをぼーっと眺めていると
ここ:https://blog.okazuki.jp/entry/2019/04/19/172010
Reactive でのイベント発火方法と、Prismのイベント発火方法が記載されているではないですか…
まさかね…と思いつつ下記を変更(XAML)
修正前:(Reactive で送信する方法)
<i:Interaction.Triggers> <i:EventTrigger EventName="PreviewDragOver"> <rpi:EventToReactiveCommand Command="{Binding PreviewDragOver}" /> </i:EventTrigger> <i:EventTrigger EventName="PreviewDragLeave"> <rpi:EventToReactiveCommand Command="{Binding PreviewDragLeave}" /> </i:EventTrigger> <i:EventTrigger EventName="PreviewDrop"> <rpi:EventToReactiveCommand Command="{Binding PreviewDrop}" /> </i:EventTrigger> </i:Interaction.Triggers>
修正後:(Prismで送る方法)
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewDragOver">
<prism:InvokeCommandAction Command="{Binding PreviewDragOver}"/>
</i:EventTrigger>
<i:EventTrigger EventName="PreviewDragLeave">
<prism:InvokeCommandAction Command="{Binding PreviewDragLeave}"/>
</i:EventTrigger>
<i:EventTrigger EventName="PreviewDrop">
<rpi:EventToReactiveCommand Command="{Binding PreviewDrop}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
変更箇所:
<rpi:EventToReactiveCommand Command="{Binding PreviewDragOver}" />
<rpi:EventToReactiveCommand Command="{Binding PreviewDragLeave}" />
↓
<prism:InvokeCommandAction Command="{Binding PreviewDragOver}"/>
<prism:InvokeCommandAction Command="{Binding PreviewDragLeave}"/>
に変更しました。
<rpi:EventToReactiveCommand Command="{Binding PreviewDrop}"/> はそのままです。
こっちは引数のEventArgs を参照しかしないので不要と判断です。
と言う訳で、Prism 側でイベントを発火すると、正しく処理できました!
EventArgs のインスタンスが直接渡されてるのかなぁ…? しかし罠だよなぁ…
しかしずいぶん昔に、Reactive系のイベント引数は「実物を渡してない」ってどこかで読んだ気がするが、気のせいだったのか探し出せない。
解決策も書いてあった気がしたんだけどなぁ…引数か何かで変更できなかったっけか…?
気のせいだったかなぁ…?
ま、これでコードビハインド無しでD&Dが出来たのでOK!!!
Prism を利用しない場合はどうするのか知りませんが、コードビハインドしかないのでは?
ここの方も同じ原因では?と思いながら、自分よりもわかりやすいと思うので拝借します。
https://maywork.net/computer/wpf-reactcommand-dd/
.net 6
Prism.Dryloc:8.1.97
Prism.Wpf:8.1.97
ReactiveProperty:9.5.0
ReactiveProperty.WPF:9.5.0