2013年06月30日

WPFサンプル:独自のドラッグ&ドロップの機能を実現する

   このエントリーをはてなブックマークに追加 Clip to Evernote
アプリケーション独自のドラッグ&ドロップの機能を実現するには、DragDropクラスを利用します。 以下、簡単なサンプルを示します。このサンプルは、

(1) TextBlockをButtonにドラッグ&ドロップすると、TextBlockのTextの内容が、ButtonのContentに複写される
(2) 左側のImageを右側のImageにドラッグ&ドロップすると左側の画像が右側のImageに複写される
(3) 左側のImageを上部 TextBlockにドラッグ&ドロップするとイメージのサイズが表示される

という3つのドラッグ&ドロップを実装しています。
以下、実行画面です。

■TextBlockをButtonにD&Dする実行例
CustomDD1
CustomDD2
CustomDD3

■左の画像を右の画像にD&Dする実行例
CustomDD4
CustomDD5
CustomDD6

■左の画像をTextBlockにD&Dする実行例
CustomDD7
CustomDD8
CustomDD9

(1)については、前回のサンプルと似ていますが、こちらは、MouseDown, DargOverといったイベントも 拾ってより実際的なコードとしています。button1_DragOverイベントハンドラで、文字列だけを受け取るようにしています。

(2)においては、image2_DragOverイベントハンドラで、右側のImageでは、TextBlockからのドラッグ&ドロップを受け取らないようにしています。

3つの例とも実用的なものではありませんが、ドラッグ&ドロップの基礎を知るサンプルとして利用できると重います。

C#のコードをお見せします。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace DragDropCustomSample {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }

        private void textBlock1_MouseDown(object sender, MouseButtonEventArgs e) {
            var textBlock = sender as TextBlock;
            DragDrop.DoDragDrop(textBlock, textBlock.Text, DragDropEffects.Copy);
        }

        private void textBlock1_Drop(object sender, DragEventArgs e) {
            ImageSource image = e.Data.GetData(typeof(ImageSource)) as ImageSource ;
            if (image != null) {
                TextBlock tb = sender as TextBlock;
                tb.Text = string.Format("{0:#.0} * {1:#.0}" , image.Width, image.Height);
            }
        }

        private void button1_DragOver(object sender, DragEventArgs e) {
            if (e.Data.GetDataPresent(DataFormats.Text))
                e.Effects = DragDropEffects .Copy;
            else
                e.Effects = DragDropEffects .None;
        }

        private void button1_Drop(object sender, DragEventArgs e) {
            (sender as Button).Content = e.Data.GetData(DataFormats.Text);
        }

        private void Image_MouseDown(object sender, MouseButtonEventArgs e) {
            var image = sender as Image;
            DataObject data = new DataObject(typeof(ImageSource ), image.Source);
            DragDrop.DoDragDrop(image, data, DragDropEffects.Copy);
        }

        private void Image_Drop(object sender, DragEventArgs e) {
            ImageSource image = e.Data.GetData(typeof(ImageSource)) as ImageSource;
            Image target = sender as Image;
            target.Source = image;
        }

        private void image2_DragOver(object sender, DragEventArgs e) {
            ImageSource image = e.Data.GetData(typeof(ImageSource)) as ImageSource;
            if (image != null )
                e.Effects = DragDropEffects .Copy;
            else
                e.Effects = DragDropEffects .None;
        }
    }
}

最後に、XAMLを示します。こちらは特筆すべきところはありません。

<Window x:Class="DragDropCustomSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="300" Width="400">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Column="0" Height="21"  Width="Auto" Text="Sample Text"
                   AllowDrop="True" HorizontalAlignment="Center" 
                   MouseDown="textBlock1_MouseDown" Drop="textBlock1_Drop" />
        <Button Grid.Column="1"  Content="Button" Height="23"
                Width="98" AllowDrop="True"
                DragOver="button1_DragOver" Drop="button1_Drop" />
        <Image Grid.Row="1" Grid.Column="0" Height="Auto" Width="60"
               Source="Castle.jpg" AllowDrop="True" MouseDown="Image_MouseDown" />
        <Image Grid.Row="1" Grid.Column="1" Height="100" Width="100"
               Opacity="1" Source="Leaf.jpg" AllowDrop="True"
               DragOver="image2_DragOver"  Drop="Image_Drop" />
    </Grid>
</Window>


WPFサンプル・目次
  

Posted by gushwell at 23:00Comments(0)TrackBack(0)

2013年06月27日

WPFサンプル:コントロール間のDrag&Drop

   このエントリーをはてなブックマークに追加 Clip to Evernote
WPFのTextBoxには、標準でドラッグ&ドロップの機能が備わっています。
AllowDropプロパティをtrueにすることで(規定値 true)、テキストを受け取ることができるようになります。TextBok間では、C#でコードを書く必要はありません。
まずは、このサンプルのスクリーンショット。

DDTextBox1

DDTextBox2

スクリーンショットから分かるように、TextBoxからTextBoxへD&Dされたテキストは移動となります。複写させたい場合は、Ctrlキーを押しながらDrag&Dropします。
XAMLは以下のとおりです。

<Window x:Class="DragDropTextBoxSample.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>
        <Grid.RowDefinitions>
            <RowDefinition Height="2*"/>
            <RowDefinition Height="2*"/>
            <RowDefinition Height="2*"/>
        </Grid.RowDefinitions>
        <TextBox Margin="10" TextWrapping="Wrap" AllowDrop="True"
                 HorizontalAlignment="Stretch" />
        <TextBox Margin="10" Grid.Row="1" TextWrapping="Wrap" AllowDrop="True"
                 HorizontalAlignment="Stretch" />
        <TextBlock Margin="10" Grid.Row="2" TextWrapping="Wrap" AllowDrop="True"
                   Background="BlanchedAlmond"
                 HorizontalAlignment="Stretch" Drop="TextBlock_Drop" />
    </Grid>
</Window>
<!-- AllowDrop を true にする(規定値)で、ドラッグ&ドロップ可能 -->

なお、このサンプルプログラムでは、TextBoxからTextBlockへのDrag&Dropも実装しています。
TextBoxからTextBlockへのDrag&Dropは、AllowDropプロパティをtrueにするだけでは 実現することができません。C#で以下のようなイベントハンドラを書く必要があります。

private void TextBlock_Drop(object sender, DragEventArgs e) {
    (e.Source as TextBlock).Text =  e.Data.GetData(typeof(string)) as string;
}

DDTextBox3

DDTextBox4


WPFサンプル・目次
  
Posted by gushwell at 23:00Comments(0)TrackBack(0)

2013年06月26日

WPFサンプル:プロパティ値の継承

   このエントリーをはてなブックマークに追加 Clip to Evernote
これまで多くのサンプルで示してきたように、XAMLでは Grid の中に StackPanel を配置したり、さらにその StackPanel の中に、Button を配置したりと、XAML で定義する UI 要素の構造は階層的になります。
この時、一部のプロパティについては、階層の上位で設定した値を、下位の要素に継承させることができます。

XAMLの例を示します。

<Window x:Class="PropertyValueInheritanceSample.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">
    <StackPanel Name="stackPanel1" Width="150"
                TextElement.FontSize="20" TextElement.FontStyle="Italic"  
                TextBlock.TextAlignment="Right" Background="#FFFFD7D7" >
        <Button Content="Button" Name="button1" Width="90" />
        <TextBlock Name="textBlock1" Text="TextBlock1" />
        <TextBlock Name="textBlock2" Text="TextBlock2" />
        <TextBlock Name="textBlock3" Text="TextBlock3" />
        <Label Content="Label" Name="label1" />
        <CheckBox Content="CheckBox" Name="checkBox1" />
        <ListBox Height="100" Name="listBox1" Width="120">
            <ListBoxItem Content="Item1" />
            <ListBoxItem Content="Item3" />
            <ListBoxItem Content="Item2" />
        </ListBox>
    </StackPanel>
</Window>


TextElement.FontSize とTextElement.FontStyle をStackPanel に設定することで、その子要素である、各コントロールのFontSize, FontStyletが継承されていることが確認できます。
また、TextBlock.TextAlignmentで、TextBoxの表示を右詰めに設定しています。
TextElement.FontSize とTextElement.FontStyle なども添付プロパティの一種です。

以下がこのXAMLの実行結果です。

PropertyValueInheritance


WPFサンプル・目次
  
Posted by gushwell at 23:00Comments(0)TrackBack(0)

2013年06月23日

WPFサンプル:イベントトリガーでアニメーションを起動する

   このエントリーをはてなブックマークに追加 Clip to Evernote
イベントトリガーを設定すると、マウスがクリックされたなどのイベントに応じて、スタイルを変更することができます。イベントトリガーは、XAMLでは、<EventTrigger>要素を用いますが、プロパティトリガーと異なり、<Setter>要素でプロパティ値を変更することができません。指定できるのは、一連のアクション(アニメーション ストーリーボード) となります。
以下にXAMLの例を示します。

<Window x:Class="EventTriggerSample.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"
        Background="Khaki">
    <Window.Resources>
        <Storyboard FillBehavior="HoldEnd" x:Key="myStoryboard" >
            <DoubleAnimation
                Storyboard.TargetName="textBox1"
                Storyboard.TargetProperty="FontSize"
                From="12" To="28" Duration="0:0:01" />
        </Storyboard>
    </Window.Resources>
    <Grid Background="White" Name="grid" >
        <Grid.Triggers>
            <EventTrigger RoutedEvent="Grid.Loaded">
                <BeginStoryboard >
                    <Storyboard FillBehavior="HoldEnd" >
                        <DoubleAnimation
                            Storyboard.TargetName="grid"
                            Storyboard.TargetProperty="Opacity"
                            From="0" To="1" Duration="0:0:01" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Grid.Triggers>
        <StackPanel Name="stackPanel" HorizontalAlignment="Left" Width="185" >
            <Button Content="Button" Height="23" Name="button1" Width="180"
                    HorizontalAlignment="Left" Margin="2" >
                <Button.Triggers>
                    <EventTrigger RoutedEvent="Button.Click">
                        <BeginStoryboard Storyboard="{Binding Source={StaticResource myStoryboard}}" />
                    </EventTrigger>
                </Button.Triggers>
            </Button>
            <TextBox Name="textBox1" Width="180" Text="TextBlock"
                     HorizontalAlignment="Left" Margin="2" FontSize="12" />
        </StackPanel>
    </Grid>
</Window>

ここでは、2つのイベントトリガーを利用してます。
ひとつは、GridのLoadedイベントが発生した時のトリガー。もう一つは、ButtonのClickイベントが発生した時のトリガーです。
Grid.Loadedでは、GridのOpacityプロパティの値を 0 から 1 に変化させています。
Window.Background には "Khaki"が設定されていますので、徐々に、Khaki から Whiteに変化します。

ふたつ目はButton.Clickで、TextBoxのFontSizeを 12 から 28 に変化させ、また 12 に戻しています。
プロパティトリガーでは、一瞬でプロパティの値が変更してしまうのに対し、イベントトリガーでは、プロパティ値をDurationで与えた時間で滑らかに変化させることができます。

※ 今回、WPFサンプルシリーズで初めてアニメーションを使いましたが、アニメーションについて別途サンプルを掲載したいと思います。
Grid.Loadedは、リソースへの定義をせずに、直接 Storyboard を Grid.Triggers要素配下に記述しています。
Button.Clickでは、Window.Resources に定義した Storyboardを指定しています。


コードビハインドには特に何も追加する必要はありません。XAMLのみで実現しています。
以下、ボタンをクリックした時のスクリーンショットです。

eventTrigger1
eventTrigger2
eventTrigger3

WPFサンプル・目次
  
Posted by gushwell at 21:22Comments(0)TrackBack(0)

2013年06月20日

WPFサンプル:マルチデータトリガーを使う

   このエントリーをはてなブックマークに追加 Clip to Evernote
データトリガーには、MultiDataTriggerというものも用意されています。
このトリガーは、バインドされたデータが一連の条件を満たしたときに、プロパティ値を適用するかアクションを実行します。

MultiDataTriggerの例を以下に示します。
WPFサンプル:データトリガーを使う」のXAMLの Style.Triggers要素に、以下の行を追加しています。

   <MultiDataTrigger>
       <MultiDataTrigger.Conditions>
           <Condition Binding="{Binding Path=Name}" Value="横浜" />
           <Condition Binding="{Binding Path=Prefecture}" Value="神奈川" />
       </MultiDataTrigger.Conditions>
       <Setter Property="Background" Value="Bisque" />
   </MultiDataTrigger>

この例では、2つの条件が一致したときに、Background プロパティの値が指定した値に変更されます。
以下、実行結果です。

DataTrigger2

XAML全体とC#のコードも掲載しておきます。

<Window x:Class="MultiDataTriggerSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:MultiDataTriggerSample"
        Title="MainWindow" Height="150" Width="300">
    <Window.Resources>
        <my:Places x:Key="PlacesData"/>
        <Style TargetType="ListBoxItem">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Prefecture}" Value="栃木">
                    <Setter Property="Foreground" Value="Blue" />
                </DataTrigger>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Path=Name}" Value="横浜" />
                        <Condition Binding="{Binding Path=Prefecture}" Value="神奈川" />
                    </MultiDataTrigger.Conditions>
                    <Setter Property="Background" Value="Bisque" />
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
        <DataTemplate DataType="{x:Type my:Place}">
            <StackPanel Width="160" Orientation="Horizontal">
                <TextBlock  Width="100"
                           Text="{Binding Path=Name}" Margin="5,0,0,0"/>
                <TextBlock  Width="50"
                           Text="{Binding Path=Prefecture}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <StackPanel>
        <ListBox Width="180" HorizontalAlignment="Center" Background="Snow"
                 ItemsSource="{Binding Source={StaticResource PlacesData}}"/>
    </StackPanel>
</Window>

using System.Collections.ObjectModel;
using System.Windows;
namespace MultiDataTriggerSample {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }
    }
        public class Places : ObservableCollection<Place> {
            public Places() {
                Add(new Place { Name = "宇都宮", Prefecture = "栃木" });
                Add(new Place { Name = "川口", Prefecture = "埼玉" });
                Add(new Place { Name = "春日部", Prefecture = "埼玉" });
                Add(new Place { Name = "日光", Prefecture = "栃木" });
                Add(new Place { Name = "横浜", Prefecture = "神奈川" });
                Add(new Place { Name = "仙台", Prefecture = "宮城" });
            }
    }
    public class Place {
        public string Name { get; set; }
        public string Prefecture { get; set; }
    }
}


WPFサンプル・目次
  
Posted by gushwell at 22:30Comments(0)TrackBack(0)

2013年06月19日

WPFサンプル:データトリガーを使う

   このエントリーをはてなブックマークに追加 Clip to Evernote
データトリガーを使うと、バインドされたデータが指定した条件を満たしたときに、プロパティ値を変更したり、アクションを実行したりすることができます。データトリガーを有効にするには、 DataTrigger要素のBinding とValueの2つのプロパティを指定する必要があります。

データトリガーのサンプルとして、ListBoxい表示されているアイテムの表示(色)がバインドさrているデータの値によって変化するサンプルを書いてみました。
今回は、C#のコードから見てください。

using System.Collections.ObjectModel;
using System.Windows;
namespace DataTriggerSample {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }
    }
    public class Places : ObservableCollection<Place> {
        public Places() {
            Add(new Place { Name = "宇都宮", Prefecture = "栃木" });
            Add(new Place { Name = "川口", Prefecture = "埼玉" });
            Add(new Place { Name = "春日部", Prefecture = "埼玉" });
            Add(new Place { Name = "日光", Prefecture = "栃木" });
            Add(new Place { Name = "横浜", Prefecture = "神奈川" });
            Add(new Place { Name = "仙台", Prefecture = "宮城" });
        }
    }
    public class Place {
        public string Name { get; set; }
        public string Prefecture { get; set; }
    }
}

PlaceとPlacesクラスを定義しています。 Placesクラスは、ObservableCollection<T>を継承させています。
このオブジェクトをListBoxにバインドします。その要素であるPlaceクラスには、Nameプロパティおよび Prefectureプロパティがあります。
XAMLでは、このPlacesのオブジェクトをListBoxにバインドそ表示しています。そしてデータトリガーを使い、Prefectureプロパティが "栃木" の場合に、対応するListBoxItemの前景が青色になるように指定しています。
XAMLを示します。

<Window x:Class="DataTriggerSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:DataTriggerSample"
        Title="MainWindow" Height="250" Width="300">
    <Window.Resources>
        <my:Places x:Key="PlacesData"/>
        <Style TargetType="ListBoxItem">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Prefecture}" Value="栃木">
                    <Setter Property="Foreground" Value="Blue" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
        <DataTemplate DataType="{x:Type my:Place}">
            <StackPanel Width="160" Orientation="Horizontal">
                <TextBlock  Width="100"
                           Text="{Binding Path=Name}" Margin="5,0,0,0"/>
                <TextBlock  Width="50"
                           Text="{Binding Path=Prefecture}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <StackPanel>
        <ListBox Width="180" HorizontalAlignment="Center" Background="Snow"
                 ItemsSource="{Binding Source={StaticResource PlacesData}}" FontSize="16" />
    </StackPanel>
</Window>

Style.Triggersコレクションプロパティの要素として、DataTriggerを指定しています。Prefecture、が"栃木"の時に、ForegroundをBlueに設定しています。

結果を以下に示します。

DataTrigger

WPFサンプル・目次
  
Posted by gushwell at 20:51Comments(0)TrackBack(0)

2013年06月16日

WPFサンプル:プロパティトリガーでコントロールのプロパティ値を変更する

   このエントリーをはてなブックマークに追加 Clip to Evernote
プロパティトリガーを使うと、あるプロパティの値が変化した時に、別のプロパティの値を変更することができます。トリガーの条件が満たされなくなると、自動的に前の状態に戻ります。
領域にマウスポインタが入ったかどうかを検出する」で、MouseEnter, MouseLeave イベントを使い、 コントロールの上にマウスが来た時に、Rectangleの見た目を変化させるサンプルをお見せしましたが、 プロパティトリガーを使っても同様のことが可能です。

ここでお見せする例は、ButtonのIsMouseOverプロパティが、trueに変更された時に、HeightとForegroundプロパティの値を変更する例です。

イベントでは、コードビハインドにイベントハンドラを記述する必要がありましたが、 Triggerを使うと、XAMLだけでこれが可能になります。

XAMLをお見せします。


XAMLを見ていただければお分かりになると思いますが、Styleを定義しています。
StyleのTriggersタグで、対象となるプロパティと、そのプロパティ値が変更になったら、 どのプロパティ値をどう変えるのかを指定しています。

以下実行結果です。

propertyTriger1
propertyTriger2
propertyTriger3

注意すべき点は、 Buttonタグで、 Height, Foreground プロパティの値を設定してある場合は、トリガーが有効に働かないということです。そのため、ボタンの高さの初期値を変更したい場合は、 Style で初期値を指定してあげる必要があります。
上の例でも、StyleでHeight値を 40 にして高さを変更しています。
  
Posted by gushwell at 22:00Comments(4)TrackBack(0)

2013年06月13日

WPFサンプル:Styleを使いListBoxの項目間に経線を引く

   このエントリーをはてなブックマークに追加 Clip to Evernote
Styleを使ったサンプル(といってもたいしたものではないですが)をもう一つ。
今度は、Styleを使いListBoxの項目間に経線を引いてみました。

Style4

左側はStyleを適用していないもの、右側がStyleを適用したListBoxです。
Styleを適用するのは、ListBoxそのものではなく、その要素の型である ListBoxItem です。
ListBoxItemのBorderThicknessを変更することで、下線を引いています。


  
Posted by gushwell at 23:00Comments(0)TrackBack(0)