LoginSignup
27
23

More than 5 years have passed since last update.

ViewのコードビハインドからViewModelの型や実装をを気にせずメソッド&プロパティにアクセスする

Posted at

例えば……

WPFで画面にドラッグ&ドロップでファイルを投げた時の処理を例として。
ViewのXAMLで

View.xaml
<Window x:Class="AmazonToYamatoB2Converter.Views.View"
        AllowDrop="True"
        Drop="View_Drop">

    <Window.DataContext>
        <vm:ViewModel/>
    </Window.DataContext>

    <Grid>
        <!-- 画面 -->
    </Grid>
</Window>

ってして、コードビハインドでドラッグ&ドロップを処理しようとするんだけど

View.xaml.cs
    public partial class View : Window
    {
        public View()
        {
            InitializeComponent();
        }

        private void View_Drop(object sender, DragEventArgs e)
        {
            var dropFileList = (e.Data.GetData(DataFormats.FileDrop) as string[]).ToList();
            // ここから先はViewModelの処理としたい
        }

    }

ドラッグ&ドロップで渡されたファイル(パス)の処理はViewModelの責務じゃないかなと思うんですよ。
Modelに渡したりとかするわけですし。
ViewModelクラスにはその為の処理としてpublic void AddDragAndDropsFiles(List<string> fileList)ってメソッドが実装されているとします。
で、そのメソッド呼ぶ為にViewからViewModelを参照するわけです。

普通にViewクラスからViewModelクラスを参照する

View.xaml.cs
        private ViewModel VM
        {
            get { return this.DataContext as ViewModel; }
        }

        private void View_Drop(object sender, DragEventArgs e)
        {
            var dropFileList = (e.Data.GetData(DataFormats.FileDrop) as string[]).ToList();
            // ここから先はViewModelの処理としたい
            this.VM. AddDragAndDropsFiles(dropFileList);
        }

まぁよくあるやつです。
これの面倒な点は、ViewModelって型を書かないと行けないって所です。
名前空間usingして、ViewModelの型を補完使って入力。(逆もある)
ViewModelの型を変更しくなったらコードビハインドも変更しないといけない。

ならInterfaceは?

書くの面倒だからコード例は出さない。
確かにそれでいいかもしれない。
でも、それも結局Interfaceの型を変更する場合同じ事なんですよね。
usingするのも変わらんし。
Iなんたらかんたらってのを沢山継承するViewModelになることないですか?

Behavior作れば?

書くの(ry
この辺りを参照して下さい。
確かにコードビハインドにコード書く必要もなくなるのいいかもね。
Interface書くのすら面倒臭がる俺にこんな長いコードを書けとか鬼か。
再利用性はあるかもしれない。
が、でもちょっと使いづらとかで機能追加してコードが読みづらくなるの、よくある話ですよね。
そもそもドラッグ&ドロップでのファイルの受け渡し程度にこんな量のコード書くの?

これでいいんじゃね?

C# 4.0からだけど、dynamicってキーワードがある。
これを使うと

View.xaml.cs
        private dynamic VM
        {
            get { return this.DataContext; }
        }

        private void View_Drop(object sender, DragEventArgs e)
        {
            var dropFileList = (e.Data.GetData(DataFormats.FileDrop) as string[]).ToList();
            // ここから先はViewModelの処理としたい
            this.VM.AddDragAndDropsFiles(dropFileList);
        }

こうなる。
何が良いって、VMはViewModelクラスじゃなくてもpublic void AddDragAndDropsFiles(List<string> fileList)メソッドを実装しているクラスならOKって所。
ViewがViewModelの型や実装を気にしなくて良い。
ViewModelの事を気にせずViewだけの実装を書いておいて、後ViewModel実装するって事も出来る。
なお、呼び出してるメソッドが実装されてなかったらコンパイルエラーは発生せず、実行時にRuntimeBinderExceptionという例外が発生します。

「C#という言語で、メソッド実装してなかったらコンパイルエラーじゃなくて実行時エラーになるのってどうなの?」
という指摘は最もだと思います。潔癖症には辛いかもしれない。
でも、InterfaceやBehaviorの作成よりは読みやすいし、書くコード量も少なくて済むので悪くないんじゃ無いかと思います。

27
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
23