trapemiyaの日記

hatenablogが新しくなったんで新規一転また2019年1月からちょこちょこ書いてます。C#中心のプログラミングに関するお話です。

Blendのビヘイビアを使った簡単な例。ViewにあるコントロールのメソッドをViewModelから実行する。

MSDNフォーラムの以下のスレッド、

WPFにはWebBrowser.DocumentTextはないのでしょうか
http://social.msdn.microsoft.com/Forums/ja-JP/wpfja/thread/9ebbdae7-8c94-40aa-8085-040ca9dd12e1

で、ViewにあるコントロールのメソッドをMVVMで実行したいという質問がありましたので、かなり簡単なサンプルですが作ってみました。

以下のサンプルを動かすには、System.Windows.Interactivity.dllとMicrosoft.Expression.Interactions.dllが必要になります。BlendをインストールされていればVisual Studioで自動的に参照設定されているので問題ありませんが、無ければ以下のかずきさんの記事を参考にして手に入れて下さい。

Visual Studioから使うExpression BlendのBehavior達
http://d.hatena.ne.jp/okazuki/20100817/1282044737

また、以下の例ではRelayCommandを使っていますが、RelayCommandを知らない方は以下にそのコードが載っています。

Model-View-ViewModel デザイン パターンによる WPF アプリケーション
http://msdn.microsoft.com/ja-jp/magazine/dd419663.aspx

私はRelayCommandではなくDelegateCommandを使うことが多いのですが、興味があれば調べてみて下さい。DelegateCommandのコードに関して、どのWebページを紹介してよいのかわからなかったので、とりあえず今回はRelayCommandを使っています。

では、以下から非常に単純なサンプルコードです。単純なので逆に骨組みがよくわかると思います。

ViewModelです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

namespace test2010wpf
{
    public class WebBrowserViewModel : IViewCommander
    {
        public WebBrowserViewModel()
        {
            ShowCommand = new RelayCommand(Show);
        }

        public ICommand ViewCommand { get; set; }

        public ICommand ShowCommand { get; private set; }

        private void Show(object obj)
        {
            ViewCommand.Execute(@"<html><body>
                    <span style=""background:green; color:white"">Behavior!!</span><html>");
        }
    }
}

ビヘイビアです。

using System.Windows.Interactivity;
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;

namespace test2010wpf
{
    public class WebbrowserBehavior : Behavior<FrameworkElement>
    {
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.DataContextChanged += new DependencyPropertyChangedEventHandler(AssociatedObject_DataContextChanged);
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.DataContextChanged -= new DependencyPropertyChangedEventHandler(AssociatedObject_DataContextChanged);
        }

        public ICommand ViewCommand { get; private set; }

        void AssociatedObject_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            ViewCommand = new RelayCommand(ViewCommandHandler);

            if (AssociatedObject.DataContext != null)
                ((IViewCommander)AssociatedObject.DataContext).ViewCommand = ViewCommand;
        }

        private void ViewCommandHandler(object obj)
        {
            ((WebBrowser)AssociatedObject).NavigateToString((string)obj);
        }
    }
}

インターフェースです。

    public interface IViewCommander
    {
        ICommand ViewCommand { get; set; }
    }

Viewです。

<Window x:Class="test2010wpf.WebbrowserView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:local ="clr-namespace:test2010wpf"
        Title="WebbrowserBehavior" Height="384" Width="550">
    <Grid>
        <WebBrowser Height="262" HorizontalAlignment="Left" Margin="33,23,0,0" Name="webBrowser1" VerticalAlignment="Top" Width="431">
            <i:Interaction.Behaviors>
                <local:WebbrowserBehavior />
            </i:Interaction.Behaviors>
        </WebBrowser>
        
        <Button Content="Show" Height="23" HorizontalAlignment="Left" Margin="326,299,0,0" Name="button1" VerticalAlignment="Top" Width="75"
                Command="{Binding ShowCommand}"/>
    </Grid>
</Window>

ボタン押す前はこんな感じ

ボタンを押した後はこんな感じ

しんぷる〜