2013年4月12日金曜日

依存関係プロパティの簡単な記述法

依存関係プロパティをいちいち記述するのは面倒なものです
簡単な書き方として、以下の操作があるようです

1. VisualStudio上でctrl - k - x を同時押し
2. コードスニペットの挿入からNetFX30を選択
3. "依存関係プロパティの挿入"を選択
        public int MyProperty
        {
            get { return (int)GetValue(MyPropertyProperty); }
            set { SetValue(MyPropertyProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MyPropertyProperty =
            DependencyProperty.Register("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0));

4. パラメータの異なる部分を直す
    public int <<< こことか < ここはICommandにする
    MyPropertyProperty < お好みで... PlotExchangeCommand とか
    を直すと、"DependencyProperty.Registerの部分も修正してくれる

2013年4月9日火曜日

ビヘイビアを使ってみる

ビヘイビアを使わないといけない局面が多そうなので、ビヘイビアの実装を試しました

今回のビヘイビアは、
- ボタンを押すとメッセージボックスを表示する
というものです
要件としてはMVVMのデータバインドでも実行できるものですが、
今回はデータバインドをかけていない"ビヘイビア"から実行します

データバインドは、"DataContext = view ViewModel()"とすることで
紐づけられていましたが、今回は"DependencyProperty"で紐づけ
を行うようです

要点は
Behavior側のコード
- クラスを作成
  public class TestBehavior : Behavior<Button>
  ボタン型に対するBeheviorを継承したクラス
- DependencyPropertyの定義
        public string Message
        {
            get { return (string)GetValue(MessageProperty); }
            set { SetValue(MessageProperty, value); }
        }
- DependencyPropertyの登録
  DependencyProperty.Register("プロパティ名", typeof(プロパティ型), typeof(所有者型));
   今回は
     プロパティ型 : stringになります
     所有者型 :  クラス名
- attach / detachの実装 > += / -= でイベントの追加をしている
 "AssociatedObject"とは、コントロール対象のオブジェクト(この場合はボタン)
     protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.Click += Alert;  // クリックイベントでAlert()を実行
        }
     protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.Click -= Alert;
        }
- イベント時に実行するハンドラの記載(↑で += されるもの)
        private void Alert(object sender, EventArgs e)
        {
            if(!string.IsNullOrEmpty(this.Message)){
                MessageBox.Show(this.Message); // メッセージボックスを表示するだけ
            }
        }

View側
- namespaceにinteractivity追加
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

- Bhaviorを追加
            <Button Content="Button" HorizontalAlignment="Left" Margin="8,8,0,0" VerticalAlignment="Top" Width="75">
                <i:Interaction.Behaviors>
                    <local:TestBehavior Message="メッセージを渡す"/>
                </i:Interaction.Behaviors>

            </Button>

最後の
<local:TestBehavior Message="メッセージを渡す"/>
で、メッセージを渡すビヘイビアを実行しています


<Window x:Class="BehaviorTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
       
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:local="clr-namespace:BehaviorTest"
        >
    <!-- 上記Title以下の2行追加 -->
    <Grid>
        <StackPanel>
            <Button Content="Button" HorizontalAlignment="Left" Margin="8,8,0,0" VerticalAlignment="Top" Width="75">
                <i:Interaction.Behaviors>
                    <local:TestBehavior Message="メッセージを渡す"/>
                </i:Interaction.Behaviors>
            </Button>
        </StackPanel>
    </Grid>
   
</Window>


---- ビヘイビア側
 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Windows.Interactivity;         // 追加
using Microsoft.Expression.Interactivity;   // 追加

using System.Windows.Controls;      // コントロール名称を参照する為
using System.Windows;               // DependencyPropertyの定義

using System.Diagnostics;

namespace BehaviorTest
{
    public class TestBehavior : Behavior<Button>
    {
        // 依存関係プロパティの登録
        public static readonly DependencyProperty MessageProperty =
            DependencyProperty.Register("Message", typeof(string), typeof(TestBehavior),
                                        new UIPropertyMetadata(null));

        // 登録される依存関係プロパティ
        public string Message
        {
            get { return (string)GetValue(MessageProperty); }
            set { SetValue(MessageProperty, value); }
        }
       
        /// <summary>
        /// アクションハンドラの記載
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Alert(object sender, EventArgs e)
        {
            if(!string.IsNullOrEmpty(this.Message)){
                MessageBox.Show(this.Message);
            }
        }

        /// <summary>
        /// アタッチされた時の処理
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.Click += Alert;
        }

        /// <summary>
        /// デタッチされた時の処理
        /// </summary>
        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.Click -= Alert;
        }
    }
}



2013年4月8日月曜日

コマンドとイベントとインプットバインディング

昨日コマンドの実装例をあげましたが、WPFには"イベント"という概念も存在します

コマンドについて先輩方のサイトを調べてみますと(MSDNだと解りにくかったり...)

コマンド : 意味論理的なイベント (ex. コピー / 貼り付けなど)
イベント : 実操作レベル (ex. クリック / キー入力など)

という違いがある模様

コマンドとしては、昨日の例のように
 <Button Command="{Binding ButtonCommand}" Content="押すとテキストが変わるよ!" />
というように、
「マウスでボタンを押すとコマンドが実行される」
を"Command="で実行出来る

が、 この場合、"左クリック押下"以外は拾えないようだ
(右クリックとかは"イベント"という事になるのか?)

イベントを拾ってコマンドを実行する方法として"インプットバインディング"というものもあるようで、
  <Window.InputBindings>
    <KeyBinding Gesture="Alt+Shift+X"
                Command="{Binding OkCommand}" />
    <MouseBinding Gesture="Ctrl+WheelClick"
                  Command="{Binding OkCommand}" />
という書き方をすると"Ctrlキーを押しながらホイールを回す"イベントをコマンドとして実行することができる様子
(こちらを参考にしました http://www.atmarkit.co.jp/ait/articles/1011/09/news102_2.html
http://www.atmarkit.co.jp/ait/articles/1103/01/news124.html )

この場合のmouseactionはこちらで定義されており
http://msdn.microsoft.com/ja-jp/library/system.windows.input.mouseaction.aspx
こちらに列挙されているactionについてはcommandで実行できるようだ

たとえば昨日のコードに
    <Grid>
        <StackPanel>
            <TextBlock Text="{Binding Text}" />
            <Button Command="{Binding ButtonCommand}" Content="押すとテキストが変わるよ!" />
            <Rectangle Width="100" Height="50" />
        </StackPanel>
        <Grid.InputBindings>
            <MouseBinding Gesture="RightClick" Command="{Binding LButtonDownCommand}" />
        </Grid.InputBindings>
    </Grid>
としておき、コード側を
        private DelegateCommand _lButtonDownCommand;
        public DelegateCommand LButtonDownCommand
        {
            get
            {
                return _lButtonDownCommand ?? (_lButtonDownCommand = new DelegateCommand(
                    () =>
                    {
                        System.Diagnostics.Debug.WriteLine("R Button Down");
                    },
                    () =>
                    {
                        return true;
                    }
                ));
            }
        }
としておくと、Gridを右クリックするとdebugコードが出る

これでも出来ない場合は、直接"イベント"を拾う事が出来る"ビヘイビア"を使う...
という認識でいいのかな....

ビヘイビアの場合、Commandに用意されていないイベントなども使う事が出来るようだ
(マウスのクリックとその座標なども知ることができるようだ)

という感じで、
- コマンド : ICommandを使用。ViewModelで簡単実装
- ジェスチャー : ある程度ICommandで対応可能
- イベント : ビヘイビアを使用...若干面倒
という感じでしょうか...



2013年4月7日日曜日

コマンドはゲッターとして実装するみたい

久々に使ってみるとかなり忘れてます...

コマンドについてメモです
"ボタンを押すとコマンドを実行して表示する"というプログラムを作ってみます

以前、メニューについて調べた際にもコマンドは使っていますが
内容についてはほとんど触れていませんでした

コマンドはデータバインドのゲッターとして実装し、
DelegateCommandのオブジェクトをreturnする模様です

newした際のdelegateは
- Execute
- CanExecute
となります

では実装してみます
例によってPrismを使っていますので
参照設定として "Microsoft.Practices.Prism"が必要になります

まずは例によって、ViewのDataContextにViewModelを設定します
namespace CommandTest_130407
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = new MainWindowViewModel();
        }
    }
}


View側にはコントロールを配置します
<Window x:Class="CommandTest_130407.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <TextBlock Text="{Binding Text}" />
            <Button Command="{Binding ButtonCommand}" Content="押すとテキストが変わるよ!" />
        </StackPanel>
    </Grid>
</Window>


ViewModel側には
/**
 * ボタンを押すとカウントが上がるだけのプログラム
 *  '13.04.07
 *
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using Microsoft.Practices.Prism.ViewModel;
using Microsoft.Practices.Prism.Commands;   // 追加

namespace CommandTest_130407
{
    public class MainWindowViewModel : NotificationObject
    {
        int _count = 0;
        string _text;
        /// <summary>
        /// テキストのデータバインド
        /// </summary>
        public string Text
        {
            get { return _text; }
            set
            {
                _text = value;
                RaisePropertyChanged(() => Text);
            }
        }



        /// <summary>
        /// コマンドのデータバインド
        /// コマンドはデータバインドのゲッターとして実装するみたい
        /// </summary>        private DelegateCommand _buttonCommand;
        public DelegateCommand ButtonCommand
        {
            get
            {
                return _buttonCommand ?? (_buttonCommand = new DelegateCommand(
                    () =>
                    {   // Execute
                        _text = string.Format("ボタン押下 : {0}回目", ++_count);
                        RaisePropertyChanged(() => Text);
                    },
                    () =>
                    {   // CanExecute
                        return true;
                    }
                ));
            }
        }
    }
}

これでボタンを押すとテキストのカウントが上がるプログラムの実装ができました