2013年6月9日日曜日

画像の表示とStretch

WPFで画像の表示をしてみます
固定の画像を表示させる場合は、xamlに以下の記述をするだけです

<Image Source="C:\Users\hogehoge\Pictures\110929-193431.jpg">

Stretchプロパティにより表示領域に対する表示方法を指定することができます
None(左上) : そのままの画像の大きさ。表示領域が画像より小さいと一部のみの表示
Fill(右上) : 上下左右を表示領域にあわせて拡大縮小。縦横比も保持されない。
Uniform(左下) : 表示領域に縦横比を保持して表示。これが一番使いそう!?
UniformToFill(右下) : 縦横比を保持した最大の表示
といったところの様子



--- xamlのコード (ファイル名(パス)の指定はお好みの画像にて!)
<Window x:Class="Graphic.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="512" Width="1024">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="256" />
            <RowDefinition Height="256" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="512" />
            <ColumnDefinition Width="512" />
        </Grid.ColumnDefinitions>
        <Image Source="C:\Users\hogehoge\Pictures\110929-193431.jpg" Stretch="None" Grid.Column="0" Grid.Row="0"/>
        <Image Source="C:\Users\hogehoge\Pictures\110929-193431.jpg" Stretch="Fill" Grid.Column="1" Grid.Row="0"/>
        <Image Source="C:\Users\hogehoge\Pictures\110929-193431.jpg" Stretch="Uniform" Grid.Column="0" Grid.Row="1"/>
        <Image Source="C:\Users\hogehoge\Pictures\110929-193431.jpg" Stretch="UniformToFill" Grid.Column="1" Grid.Row="1"/>
    </Grid>
</Window>

2013年6月4日火曜日

TextBlockの文字を修飾する

文字を修飾する方法の良いサンプルがMSDNに掲載されていましたので真似してみます

ボタンの文字を"Run"で修飾してみます
- Runで文字の属性変更
- <Run TextDecorations="****">で修飾
の模様
日本語ではベースラインとアンダーラインの区別はわかりにくいですが、アルファベットを使う場合は効果的ですね

<Window x:Class="StringDecorate.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>
        <Button Width="200" Height="150">
            <TextBlock>
                ふつーのTextBlock<LineBreak />
                <Run FontWeight="Bold" FontSize="13">フォントサイズ+Bold</Run><LineBreak />
                <Run TextDecorations="Underline">アンダーライン</Run><LineBreak />
                <Run TextDecorations="Strikethrough">打消し線</Run><LineBreak />
                <Run TextDecorations="Overline">オーバーライン</Run><LineBreak />
                <Run TextDecorations="Baseline">gベースライン</Run>
                <Run TextDecorations="Underline">gアンダーライン</Run>
            </TextBlock>
        </Button>
    </Grid>
</Window>


詳しくはMSDNのこちら参照
http://code.msdn.microsoft.com/windowsdesktop/XAML-WPF-165daa55

2013年5月14日火曜日

DataGridで表示してみる

昨日と同じ内容を、DataGridで表示してみます
        <DataGrid ItemsSource="{Binding People}" />
とするとbindingしている内容が表示される模様

変わっているのは、表題部分をクリックするとデータをソートしてくれるところが便利かと思いましたが、他は何が違うのかは調べてみたいと思います

ListViewのようにHeaderは明示的に設定してませんが、メンバ名が表示される模様
ViewModel側は特に変えていないのでView側から見ていきます

--- View
<Window x:Class="DataGrid_130512.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:DataGrid_130512"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <l:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <!-- 基本的にここを変えただけ -->
        <DataGrid ItemsSource="{Binding People}" />
    </Grid>
</Window>

--- ViewModel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Prism.ViewModel;
using System.Collections.ObjectModel;
using System.Windows;

namespace DataGrid_130512
{
    class MainWindowViewModel : NotificationObject
    {
        ObservableCollection<Person> _people = new ObservableCollection<Person>();
        public ObservableCollection<Person> People
        {
            get { return _people; }
            set { _people = value; }
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MainWindowViewModel()
        {
            // 表示データの生成
            _people.Add(new Person("Stan Hansen", 6));
            _people.Add(new Person("Bruiser Brody", 5));
            _people.Add(new Person("Terry Funck", 10));
        }

        /// <summary>
        /// 選択されている人
        /// </summary>
        public Person SelectedPerson { get; set; }

        public void Execute()
        {
            if (SelectedPerson != null)
            {
                MessageBox.Show(SelectedPerson.Name);
            }
            else
            {
                MessageBox.Show("選択されていません");
            }
        }
    }

    // ListBoxに表示するデータ
    public class Person
    {
        public string Name { get; set; }
        public int TitleCount { get; set; }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="name"></param>
        /// <param name="count"></param>
        public Person(string name, int count)
        {
            Name = name;
            TitleCount = count;
        }
    }
}


2013年5月13日月曜日

ListViewで1行毎にシマシマ表示にしてみる

ListViewでAlternationPropertyを設定するとシマシマ表示が出来るらしいので試してみます

ListViewのItemContainerStyleを設定するようです

--- View側
<Window x:Class="ListViewTest_130508.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:ListViewTest_130508"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <l:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <ListView x:Name="listView1"
                 ItemsSource="{Binding People}"
                 SelectedItem="{Binding SelectedPerson}"
                 SelectionMode="Multiple"
                 AlternationCount="2" >
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Header="Name"
                                        Width="150"
                                        DisplayMemberBinding="{Binding Name}" />
                        <GridViewColumn Header="Title Count"
                                        Width="100"
                                        DisplayMemberBinding="{Binding TitleCount}" />
                    </GridView.Columns>
                </GridView>
            </ListView.View>
            <!-- AlternationCountプロパティを使ってみる -->
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Style.Triggers>
                        <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                            <Setter Property="Background" Value="Aqua" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </ListView.ItemContainerStyle>
        </ListView>
    </Grid>
</Window>

--- ViewModel側 (こちらは特に変更はなしです)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Prism.ViewModel;

using System.Collections.ObjectModel;
using System.Windows;

namespace ListViewTest_130508
{
    public class MainWindowViewModel : NotificationObject
    {
        ObservableCollection<Person> _people = new ObservableCollection<Person>();
        public ObservableCollection<Person> People
        {
            get { return _people; }
            set { _people = value; }
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MainWindowViewModel()
        {
            // 表示データの生成
            _people.Add(new Person("Stan Hansen", 3));
            _people.Add(new Person("Bruiser Brody", 5));
            _people.Add(new Person("Terry Funck", 10));
        }

        /// <summary>
        /// 選択されている人
        /// </summary>
        public Person SelectedPerson { get; set; }

        public void Execute()
        {
            if (SelectedPerson != null)
            {
                MessageBox.Show(SelectedPerson.Name);
            }
            else
            {
                MessageBox.Show("選択されていてません");
            }
        }
    }

    // ListBoxに表示するデータ
    public class Person
    {
        public string Name { get; set; }
        public int TitleCount { get; set; }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="name"></param>
        /// <param name="count"></param>
        public Person(string name, int count)
        {
            Name = name;
            TitleCount = count;
        }
    }
}


2013年5月12日日曜日

ListViewを使ってみる

前回は(なんとなく)ListBoxを使ってItemsControlの表示をしてみましたが、複数"列"のデータを表示する場合はListViewを使うようです

MSDNでもどちらをチョイスするかの基準が記載されています
http://msdn.microsoft.com/ja-jp/library/aa511485.aspx

以下抜粋します
リスト ボックスリスト ビュー
データ型データとプログラム オプションの両方。データのみ。
コンテンツラベルのみ。ラベルおよび補助データ。複数列の場合もあります。
対話操作選択に使用。選択に使用。ただし、多くの場合はデータの表示と対話操作のために使用されます。ドラッグ ソースまたはドロップ ターゲットとなることができます。
提示方法固定。ビューの変更、グループ化、列ごとの並べ替え、列の幅と順序の変更が可能です。
  • 一覧に表示されるものが、プログラム オプションではないデータかどうか。該当しない場合は、代わりにリスト ボックスを使用することを検討します。
  • ビューの変更、グループ化、列ごとの並べ替え、列の幅と順序の変更が必要かどうか。該当しない場合は、代わりにリスト ボックスを使用します。
  • コントロールが、ドラッグ ソースまたはドロップ ターゲットとして機能する必要があるかどうか。該当する場合は、リスト ビューを使用します。
  • リスト アイテムをクリップボード経由でコピーする必要があるかどうか。該当する場合は、リスト ビューを使用します。
 ---
ちょっと使ってみます

--- ViewModel側(ListBoxのコードにもうひと項目追加)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Prism.ViewModel;

using System.Collections.ObjectModel;
using System.Windows;

namespace ListViewTest_130508
{
    public class MainWindowViewModel : NotificationObject
    {
        ObservableCollection<Person> _people = new ObservableCollection<Person>();
        public ObservableCollection<Person> People
        {
            get { return _people; }
            set { _people = value; }
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MainWindowViewModel()
        {
            // 表示データの生成
            _people.Add(new Person("Stan Hansen", 3));
            _people.Add(new Person("Bruiser Brody", 5));
            _people.Add(new Person("Terry Funck", 10));
        }

        /// <summary>
        /// 選択されている人
        /// </summary>
        public Person SelectedPerson { get; set; }

        public void Execute()
        {
            if (SelectedPerson != null)
            {
                MessageBox.Show(SelectedPerson.Name);
            }
            else
            {
                MessageBox.Show("選択されていてません");
            }
        }
    }

    // ListBoxに表示するデータ
    public class Person
    {
        public string Name { get; set; }
        public int TitleCount { get; set; }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="name"></param>
        /// <param name="count"></param>
        public Person(string name, int count)
        {
            Name = name;
            TitleCount = count;
        }
    }
}

--- View側
"<GridViewColumn>"の部分がミソでしょうか

<Window x:Class="ListViewTest_130508.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:ListViewTest_130508"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <l:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <ListView x:Name="listView1"
                 ItemsSource="{Binding People}"
                 SelectedItem="{Binding SelectedPerson}"
                 SelectionMode="Multiple" >
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Header="Name"
                                        Width="150"
                                        DisplayMemberBinding="{Binding Name}" />
                        <GridViewColumn Header="Title Count"
                                        Width="100"
                                        DisplayMemberBinding="{Binding TitleCount}" />
                    </GridView.Columns>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>



2013年5月6日月曜日

ItemsControlとObservableCollectionによる表示

ListViewなど複数のデータを表示する場合、DataSourceとしてObservableCollectionを使うとデータに変化があった場合にView側に通知されるので便利なようです。

まずは簡単な使い方から試していこうかと思います

以下の例は
- ViewModel側でObservableCollectionであるPeopleを初期化
- View側は↑をItemsSourceとしてDataBindし、ListBox.ItemTemplateで単一データを表示
- 選択状態は SelctedItemでDataBind
という感じの動作(というか表示)としています

今回はDataContextをコードビハインドで行わずにxamlで書いています
(これでもOKのようなので)

--- MainWindowViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Prism.ViewModel;

using System.Collections.ObjectModel;
using System.Windows;


namespace ListViewTest_130430
{
    public class MainWindowViewModel
    {
        ObservableCollection<Person> _people = new ObservableCollection<Person>();
        public ObservableCollection<Person> People {
                    get { return _people; }
                    set { _people = value; }
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MainWindowViewModel()
        {
            // 表示データの生成
            ObservableCollection<Person> people = new ObservableCollection<Person>();
            string[] names = new string[]{ "Stan Hansen", "Bruiser Brody", "Terry Funck", "Dick Murdoch"};
            foreach (string name in names)
            {
                Person p = new Person();
                p.Name = name;
                _people.Add(p);
            }
        }

        /// <summary>
        /// 選択されている人
        /// </summary>
        public Person SelectedPerson { get; set; }

        public void Execute()
        {
            if (SelectedPerson != null)
            {
                MessageBox.Show(SelectedPerson.Name);
            }
            else
            {
                MessageBox.Show("選択されていてません");
            }
        }
    }

    // ListBoxに表示するデータ
    public class Person
    {
        public string Name { get; set; }
    }
}


--- MainWindow.xaml
<Window x:Class="ListViewTest_130430.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:ListViewTest_130430"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <l:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <ListBox x:Name="listBox1"
                 ItemsSource="{Binding People}"
                 SelectedItem="{Binding SelectedPerson}" >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <ContentControl Content="{Binding Name}">
                    </ContentControl>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

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;
                    }
                ));
            }
        }
    }
}

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

2013年2月23日土曜日

テンプレートを使ってみる

参照の追加やusingの記述などで同じような記述を毎回するのは面倒なので、VisualStudioのテンプレート機能を使ってみました

カスタマイズはいろいろ出来るようですが、理解できなかったのでとりあえず...
1. 適当なソリューションを新規作成する("Templete"という名前で良い...特に後で影響しないようなのでなんでもよいようです)
2.  参照やusingの記述をしたり、毎回追加するファイルを追加しておくなどを行う(MVVMなら***ViewModel.csとか)
3. "ファイル" -> "テンプレートのエクスポート"を選択
4. ダイアログが出るのでひたすらデフォルトで"次へ"
5. どこかにzipファイルで出力される模様
> 追記 : MyDocumentsの↓の位置にzipファイルとして作成される
> C:\Users\xxxxx\Documents\Visual Studio 2012\Templates\ProjectTemplates\Visual C#
> 別のマシンで使う場合は同じ場所にコピーすれば使えるみたい

使う場合は、ふつーに新規プロジェクトの作成をしようとすると↑で作成したテンプレートが下の方に表示されるのでそちらを選択すると、いい感じでTemplateで作成した内容がデフォルトになったプロジェクトが生成される模様
(namespaceなどは新規作成にあわせてくれるという意味で)

カスタマイズは奥が深いみたいですが、↑の程度でも適当に使えるので活用してみようかと思います



2013年2月7日木曜日

XAML内でのデータバインド

最も簡単な例として、定番の"スライダーとテキストをbind"してみました

<Window x:Class="_130206_xamlDataBind.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>
            <Slider VerticalAlignment="Top" HorizontalAlignment="Center" Width="300" Margin="10"
                    Name="slider" Value="{Binding textValue}" />
            <TextBlock VerticalAlignment="Top" HorizontalAlignment="Center"
                    Text="{Binding ElementName=slider, Path=Value}" />
        </StackPanel>
    </Grid>
</Window>

2013年2月4日月曜日

BehaviorでViewからViewModelのコマンドを実行&パラメータ渡し

ViewからViewModelのコマンドを実行する際に、Behaviorというものを使う方法があるとのことですので動かしてみました(丸パクリですが...)

手順としては
1. 参照設定の追加
Blendの機能なので、Interactivity.dllを参照する
"プロジェクトの参照設定"の"ブラウズ"にて"参照(B)"から
C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\.NETFramework\v4.0\Libraries
の以下の2つのdllを追加
Microsoft.Expression.Interactions.dll
System.Windows.Interactivity.dll
を選択して"追加"する

2. ***Behavior.cs を作成(ここにbeheviorの処理を書いていきたい)

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

4. 監視対象の型のBehaviorを継承したクラスを作成
using が足りないので以下を追加
using System.Windows.Controls;      // コントロール名称を参照する為
using System.Windows;               // DependencyPropertyの定義

監視対象の型のBehaviorを継承したクラスを作成
    public class TestBehavior : Behavior<Button>

5. 依存関係プロパティの定義と登録
作成したクラス内に依存関係プロパティを登録するコードを追加
戻りは"依存関係プロパティ識別子"で"後でプログラムで値を設定したり、メタデータを取得したりする際に、この識別子を使用して依存関係プロパティを参照できます"とのこと
        public static readonly DependencyProperty MessageProperty =
            DependencyProperty.Register("Message" , typeof(string), typeof(TestBehavior),
                            new UIPropertyMetadata(null));

6. (登録される)依存関係プロパティ
        // 公開プロパティ
        private string _message;
        public string Message
        {
            get { return (string)GetValue(MessageProperty); }
            set { SetValue(MessageProperty, value); }
        }

7. 独自ハンドラ(イベント発生時にやりたいこと)追加
        private void Aleart(object sender, EventArgs e)
        {
            if(!string.IsNullOrEmpty(this.Message)){
                MessageBox.Show(this.Message);
            }
        }

8. アタッチ・デタッチ時のハンドラを登録
        /// <summary>
        /// アタッチされた時の処理
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.Click += Alert;
        }

        /// <summary>
        /// デタッチされた時の処理
        /// </summary>
        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.Click -= Alert;
        }
9. xamlにBehaviorを呼び出す処理を記載
            <Button Content="Button" HorizontalAlignment="Left" Margin="8,8,0,0" VerticalAlignment="Top" Width="75">
                <i:Interaction.Behaviors>
                    <local:TestBehavior Message="メッセージを渡す"/>
                </i:Interaction.Behaviors>
            </Button>


とりあえずこれで
- ボタンをクリックした時にBehavior側の処理を呼び出す
という事が出来るようです

BreakPointを適当に張ってみると
1. 起動時にアタッチのハンドラが呼ばれる
  ここで"ボタンクリックイベントにメソッドが登録される"模様
2. ボタンを押下すると登録されたメソッドが呼ばれる
  この時、すでに依存関係プロパティにはxaml側の
  "Message="メッセージを渡す"
  という部分が反映されている
という動きの模様

動かしたソースは以下の通り
TestBehavior.cs側
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)
        {
            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;
        }
    }
}


xaml側のコード
<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="メッセージを渡す"/>
         <!-- ↑の"Message"がコードにバインドされている模様 -->
                </i:Interaction.Behaviors>
            </Button>
        </StackPanel>
    </Grid>
</Window>


2013年1月28日月曜日

メニューのコマンドをViewModelに実装

1つ前の記事に記載したメニューの書き方から、実際にプログラム側で処理を行う部分を実験してみました。

MVVMモデルですとViewModelに相当する部分ですので、ファイル名は"MainWindowViewModel.cs"としています。

コマンドの記述としては、CanExecuteとExecuteが肝なのですが、こちらの書き方が諸説あるようで、まずは(調べると)ポピュラーと思われるパターンで実装してみました

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;     // IComand用
using System.Windows;            // Dialog表示用(表示しなければ不要)

namespace _130126Project
{
    public class MainWindowViewModel
    {
        class OkCommandImpl : ICommand
        {
          public bool CanExecute(object parameter) { return true; }
          public event EventHandler CanExecuteChanged;

          public void Execute(object parameter)
          {
            MessageBox.Show("コマンドが実行されました。");
          }
        }

        public ICommand OkCommand { get; private set; }



        // ViewModelのコンストラクタ
        public MainWindowViewModel()
        {
            // public ICommand型の公開プロパティに
      // OkCommandImplクラスのオブジェクトを設定
            this.OkCommand = new OkCommandImpl();
        }

    }
}

そして、コードビハインドと言われるコード(MainWindow.xaml.cs)のコンストラクタに
 DataContext = new MainWindowViewModel();
を記述します

    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new MainWindowViewModel();   // ここだけ追加
        }
    }

 とりあえずこれで
- メニューの"ファイル -  実行"を選択すると
- MainWindowViewModel.csのICommand型の"OkCommandの
動きます(これならprismを使わなくても動きますね)

もうちょっといい書き方があるかなぁと調べていると、
- DelegateCommandを使うと簡潔に記載できる
との記事が出てきます
さらに
- 以前はDelegateCommandを自作してたけど、prismに入っているから便利
という記事も出てきたりしました

いろいろ調べた末に↑のコードを以下のように変更して動作する事が出来ました
以下ではPrismを使っているのでコメントにある通りに、dllの参照設定を追加する必要があります
(面倒なので、2つ前の記事で解凍したprism関連のdllを全て選択してしまっていますが、使うのは以下のusingで記載したdllだけだと思います)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.ComponentModel;    // INotifyPropertyChange用
using Microsoft.Practices.Prism.Commands;    // prism用(予めdllを参照設定しておく)
using Microsoft.Practices.Prism.ViewModel;  // NotificationObject用

namespace _130126Project{
    public class MainWindowViewmodel : NotificationObject
    {
        private DelegateCommand<object> _okCommand;

        public DelegateCommand<object> OkCommand
        {
            get
            {
                return _okCommand ?? (_okCommand = new DelegateCommand<object>(
                    (param) =>
                    {   // Execute
                        MessageBox.Show("コマンドが実行されました");
                    },
                    (param) =>
                    {    // CanExecute
                         return true;    // 実行しない場合はfalseを返す。動的に変更可                    }
                ));
            }
        }
    }
}

動作としては以下のような感じのようです(デバッガでbreakさせた時の挙動)
0. View(xaml)の
     Command="{Binding OkCommand}"
  と
  DelegateCommand<object> OkCommand が紐づけ
1. オブジェクト作成時(プログラム起動時)にOkCommandのgetterにWPFがアクセス
  _okCommandはnullなのでDelegateCommandでnewします
2. menu表示時("ファイル"を押下してペロッと表示される瞬間)にWPFがCanExecuteを聞きに来る
  今回はtrueが返るのでメニューの"実行"も黒文字で表示される
3. "実行"を選択するともう一度"CanExecute"を聞きに来て、すぐにExecuteを実行
  結果、MessageBoxが表示される

"1"の部分が以前は自作されていたようでうすが、prismでサポートされたのでこちらの"DelegateCommand"を使うようになったようです

View-ViewModelのコマンドはこれで開通したので、次はModelとViewModelの接続について試していこうと思います





2013年1月27日日曜日

ChainLPの設定for Kindle PaperWhite

本来はソフト作成のtipsをメモっておこうと思ったのですが、早くも脱線
先月購入したKindleのChainLPでの変換設定メモです
(ChainLPは本ブログの題名とは無縁な素晴らしいソフトです)

表題で検索するといろいろな方が試したベストの設定が出てくるのですが、自分用に要点をメモ

準備
- ChainLPの他に、mobi形式を出力する場合はamaxonご提供のkindlegen.exeが必要
http://www.amazon.com/gp/feature.html?docId=1000234621&tag=wp-amazon-associate-20

入力
- PDFならarc、 jpegならdirを選択

出力
- kindleなのでmobiを選択
 (readerとかならePub)

サイズ
- 758 x 1024 : 通常

ページ補正
- 小説優先(文字が読みやすいとのこと)

ガンマ補正
- チェック / 自動レベルもチェック

これで"出力"ボタンを押すと出力先ディレクトリを尋ねられるので指定すれば変換開始

素晴らしいソフトです!!
(作者さんならびに設定で試行錯誤された先人にも感謝!)


メニューをつけてみる

Windows Formでは適当にツールボックスから貼るだけでメニューが生成できていましたが、WPFの場合はそうはいかない模様です

DockPanelのDockをTopにして配置していくのがよさそうです
以下の例では
- Menuを2項目配置 ("ファイル"と"オプション"がメニューバーに表示)
- それぞれに子要素を"MenuItem"で配置
- MenuItemは
  Header要素に、"メニューに表示される文字"
  実行させたい動作を"Command="{Binding コマンド名}" "
 として実装する模様
 画像なども貼れるようですが、一番シンプルなのはこんな感じで...

    <Grid>
        <DockPanel>
            <Menu Name="menuFile" DockPanel.Dock="Top">
                <MenuItem Header="ファイル">
                    <MenuItem Header="実行" Command="{Binding OkCommand}" />
                    <MenuItem Header="書き込み" Command="{Binding WriteCommand}"/>
                    <MenuItem Header="転送" Command="{Binding TransferCommand}"/>
                    <MenuItem Header="切り取り" Command="ApplicationCommands.Cut"/>
                </MenuItem>
                <MenuItem Header="オプション">
                    <MenuItem Header="設定" />
                    <MenuItem Header="情報" />
                </MenuItem>
            </Menu>
            <TextBox Name="textBoxWrite" DockPanel.Dock="Top"/>
        </DockPanel>
    </Grid>

Prismをインストールしてみる


最新はprism 4.1みたいなのでこちらからダウンロード
http://www.microsoft.com/en-us/download/details.aspx?id=28950

ダウンロードしたファイルをダブルクリックすると解凍されるので、好きな場所に置きます

システムに登録しておくとあとあと楽みたいだけど、とりあえずプロジェクトの"参照"->"参照の追加" -> "ブラウズ"でも設定できるようなのでこちらで(desktop下のdllをすべて選択して)追加

これで使えるようになる模様

※ ちなみに諸事情にて、VisualStudio10 for WindowsPhoneを入れた関係か予めBlendがinstallされています。もしかするとBlend(SDK)が入っていない場合はそちらを入れる必要があるかも....

はじめました

ブログ作ってみました
プログラム関連のメモを置いておこうかなと思っています