goo blog サービス終了のお知らせ 

いつもどこかでデスマーチ♪

不定期に、私の日常を書き込みしていきます。

ReactiveProperty で TextBox に対して Drop 処理が出来ない!?

2024年07月04日 18時46分05秒 | .NET系
結論:
引数の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
コメント    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« Visual Studio の ホットリロ... | トップ | C# WPFのLoaded イベントが複... »
最新の画像もっと見る

コメントを投稿

ブログ作成者から承認されるまでコメントは反映されません。

.NET系」カテゴリの最新記事