[WPF] Xaml で親要素のプロパティをバインディングする

 Xaml ではコントロールのプロパティなどに別のコントロールのプロパティをバンディングできます。名前のあるコントロールのプロパティを参照する際はその名前を利用する事ができますが、単純に親のプロパティを引き継ぎたい場合もあります。親コントロールのプロパティを参照する方法です。
 

■ 概要


 RelativeSourceMode=FindAncestoAncestorType に参照したい親コントロールの型を設定します。また参照したい親コントロールまでに間に親コントロールの型のコントロールがある場合、AncestorLevel を指定します。
 次の一つ目の Label の文字色は Red、二つ目も Red、三つ目は LightGreen になります。
 

■ コード


<Grid Background="Red">
    <Label Content="sample" Background="Blue" Foreground="{Binding Background,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}}"/>
</Grid>

<Grid Background="LightGreen">
    <Grid Background="Red">
        <Label Content="sample" Background="Blue" Foreground="{Binding Background,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid,AncestorLevel=1}}"/>
    </Grid>
</Grid>

<Grid Background="LightGreen">
    <Grid Background="Red">
        <Label Content="sample" Background="Blue" Foreground="{Binding Background,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid,AncestorLevel=2}}"/>
    </Grid>
</Grid>
広告

[WPF] 複数のコントロールのサイズを統一する

 Xaml ではコントロールのプロパティなどに別のコントロールのプロパティをバンディングできます。複数のコントロールのサイズなどを統一したい場合、この機能を利用すると一つのコントロールのサイズを変更するだけでミスなくすべてのコントロールのサイズを変える事ができ、メンテナンスのメリットがあることがあります。
 

■ 概要


 バインディングの設定で ElementName に参照したいコントロールの名前を設定します。
 次の例では、最初の背景色が RedGridHeight を変更することで他の二つの Grid も同様の高さに変更されます。
 

■ コード


<Grid Background="Red" x:Name="grid1" Height="20"/>
<Grid Background="Green" Height="{Binding Height, ElementName=grid1}"/>
<Grid Background="Blue" Height="{Binding Height, ElementName=grid1}"/>

[WPF] DatePicker のカレンダーを大きくする

 次のように DatePicker 自体を拡大する場合、カレンダーも同じように大きくなります。

<DatePicker>
    <DatePicker.LayoutTransform>
        <ScaleTransform ScaleX="2" ScaleY="2"/>
    </DatePicker.LayoutTransform>
</DatePicker>

 しかし逆に言うとこの場合は、本体自体も大きくしなければならず、カレンダーだけを大きくすることはできません。また、コントロールを大きく表示したい場合に、拡大をするのではなくフォントサイズを大きくする方法をとることのあるそうです。この場合、本体自体は大きくなりますがカレンダーは大きくなりません。例えば次のようなコードの場合がそれにあたります。

<DatePicker FontSize="20"/>

 

■ カレンダーだけを大きくする

 DatePickerCalendarStyle でカレンダーのスタイルと変更できます。ここで LayoutTransform を指定しカレンダーを大きくします。

<DatePicker>
    <DatePicker.CalendarStyle>
        <Style TargetType="Calendar">
            <Setter Property="LayoutTransform">
                <Setter.Value>
                    <ScaleTransform ScaleX="2" ScaleY="2"/>
                </Setter.Value>
            </Setter>
        </Style>
    </DatePicker.CalendarStyle>
</DatePicker>

[WPF] DataGrid の行の背景色を交互に変える

 かつて在りし日の Windows フォーム では、DataGridView が非常に人気があり、その中でも、行の背景を交互に変える事が特に人気でした。
 具体的には、奇数行の背景色だけを設定するプロパティがあり、それが活用されていたものと思います。
 Windows フォーム では AlternatingRowsDefaultCellStyleBackColor を指定することで実装できました。
 
 WPF ではもっと簡単に、DataGridAlternatingRowBackground というプロパティを持っています。
 ここにお好みの色を設定すれば OK です。
 

■ コード

コードは次のようになります。

<Window x:Class="WpfApp1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="Window1" Height="300" Width="300">
    <Grid>
        <DataGrid ItemsSource="{Binding}" AlternatingRowBackground="Azure"/>
    </Grid>
</Window>

[WPF] xaml でコントロールのアクセス修飾子を指定する

WPF で xaml により UI を定義した場合、各コントロールのアクセス修飾子は規定で internal になります。
これを変更する場合、 x:FieldModifier を使用します。

■ 例

次の例は、 label をいう名前の Label のアクセス修飾子を protected にしています。

<Label x:Name="label" x:FieldModifier="protected"/>

[WPF] ファイルダイアログを使う

WPF ではファイルダイアログは
「開く」ダイアログは Microsoft.Win32 名前空間の OpenFileDialog クラスを使用します。
「名前を付けて保存」ダイアログは Microsoft.Win32 名前空間の SaveFileDialog クラスを使用します。

使い方は次のようになります。 (サンプルは C# コードです)
いずれの場合でも、using に using Microsoft.Win32; を追加してください。

■ OpenFileDialog / SaveFileDialog

注意

WPF ではファイルダイアログは Microsoft.Win32 名前空間のクラスを使用します。
しかし OpenFileDialogSaveFileDialog は同名のクラスが System.Windows.Forms アセンブリ内の System.Windows.Forms 名前空間にも存在します。
誤って System.Windows.Forms 名前空間のクラスを使ってしまうことがあるようです。
ご注意ください。

[WPF] ボタン押下時の処理中に画面操作を受け付けなくする

C# には async/await という素晴らしい仕組みがあり、時間のかかる処理を行う際にもアプリそのものは固まらないようにすることが簡単にできます。
ここでアプリが固まるというのは、いわゆるタイトルバーに「応答なし」と出るヤツです。

■ async/await を使用して「応答なし」にならないボタン

例えば次のように書けば 5 秒かかる処理をボタン押下で行っても「応答なし」にはなりません。
ここでは xaml に、x:Name=”button” というボタンがあると思ってください。

private async void button_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Start!");
    await Task.Delay(5000);
    MessageBox.Show("End!!");
}

これで、「応答なし」にならずに、5 秒間の処理ができます。
しかし、「応答なし」にならない代わりに、処理中でもボタンを何度も押せてしまいます。

人力でクリックできる速度より早く完了する処理であれば問題はないでしょう。
しかし、時間がかかる処理を行う場合は、連打されると都合が悪い場合もあるでしょう。
ボタン連打ばかりでなく、他のボタンを押されるなどでいろいろ整合性が取れなくなってしまう場合などもあるでしょう。

今回は、豪快に処理中は Window 内の UI 全体を使用不可にしてみましょう。

■ 基本方針

既に、ボタン押下時の処理は(コードビハインドに)実装されているものとします。
それも何か所も存在するし、今後も増えて行くとします。
これをなるべく省力で変更する方法として、Func を受け取り、Func の実行前に UI をロックし、Func の実行後に UI のロックを解除するメソッドを作りこれを使用するようにします。

■ 処理中に UI をロックするコード

まず、LockUI メソッドを次のように作ります。今回は、マウスカーソルもグルグルするようにしてみました。
次に button_Click2 メソッドを作り、button_Click メソッドの内容を移動します。
最後に、button_Click の中で、LockUI を button_Click2 を引数に渡し実行します。

private async Task LockUI(Func<Task> act)
{
    var topElm = ((UIElement)VisualTreeHelper.GetChild(this, 0));
    var oldEnabled = topElm.IsEnabled;
    var oldCursor = this.Cursor;
    try
    {
        this.Cursor = Cursors.Wait;
        topElm.IsEnabled = false;
        await act();
    }
    finally
    {
        topElm.IsEnabled = oldEnabled;
        this.Cursor = oldCursor;
    }
}

private async void button_Click(object sender, RoutedEventArgs e)
{
    await LockUI(async ()=> { await button_Click2(); });
}

private async Task button_Click2()
{
    MessageBox.Show("Start!");
    await Task.Delay(5000);
    MessageBox.Show("End!!");
}

これで、処理中に UI がロックされるボタンができました。