XamDataGridの各列の幅をFontSizeに応じて変更する

フォントサイズに応じてXamDataGridの各列の幅を自動で変更する方法をご紹介します。

今回は、XamDataGridのフォントサイズをスライダーの値に連動させ、さらに、列幅を自動調整してみましょう。

Fieldに対してXamDataGridのFontSizeをバインドすることはできません。Fieldはビジュアルツリーに載らないオブジェクトだからです。

代わりに、XamDataGridのTagにXamDataGridをバインドし、コンバーターを使って列幅調整をします。

 

まず、Xaml側です。

<StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock VerticalAlignment="Center" Text="FontSize: "/>
        <ig:XamNumericSlider
            x:Name="xamNumericSlider1" VerticalAlignment="Center"
            Width="150"
            MinValue="5" MaxValue="50" Value="11"/>
        <TextBlock VerticalAlignment="Center" Text="{Binding ElementName=xamNumericSlider1, Path=Value}"/>
    </StackPanel>
    <igDP:XamDataGrid
        x:Name="xamDataGrid1"
        HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
        BindToSampleData="True"
        FontSize="{Binding ElementName=xamNumericSlider1, Path=Value, Mode=TwoWay}" Loaded="xamDataGrid1_Loaded"
        >
        <igDP:XamDataGrid.Tag>
            <MultiBinding Converter="{StaticResource FontSizeToFieldWidthConverter}" Mode="OneWay">
                <Binding RelativeSource="{RelativeSource Self}"/>
                <Binding ElementName="xamNumericSlider1" Path="Value"/>
            </MultiBinding>
        </igDP:XamDataGrid.Tag>
    </igDP:XamDataGrid>
</StackPanel>
XamNumericSliderがスライダーです。

XamDataGridのFontSizeがXamNumericSliderのValueにバインドされています。XamNumericSliderの値の変化に応じてXamDataGridのFontSizeも変化するようにしています。

XamDataGridのTagにMultiBindingをしています。バインドしているのは、XamDataGrid自身と、XamNumericSliderのValueです。XamNumericSliderもバインドすることで、XamNumericSliderの値が変わるたびにコンバーターが呼び出されるようにしています。

バインドターゲットからバインドソースへのバインドは不要なので、ModeはOneWayにしています。

 

続いて、コンバーターです。

public class FontSizeToFieldWidthConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        XamDataGrid grid = values[0] as XamDataGrid;

        if(grid.FieldLayouts.Count == 0)
        {
            return Binding.DoNothing;
        }

        FieldCollection fields = grid.FieldLayouts[0].Fields;

        for(int i = 0; i < fields.Count; i++)
        {
            fields[ i ].PerformAutoSize();
        }

        return Binding.DoNothing;
    }
}

渡されてきたXamDataGridを使って、FieldCollectionを取り出し、各フィールドに対してPerformAutoSizeメソッドを呼び出しています。PeformAutoSizeメソッドは列に表示されているデータの長さに応じて列幅を調整するメソッドで、今回のシナリオにぴったりのメソッドです。

バインドターゲットのTagには値を返す必要がないので、すべての処理が終わった後にBinding.DoNothingを返しています。

 

結果

初期ロード時

 

スライダー動かすと…、スライダーの値に応じてXamDataGridのフォントが大きくなるのはもちろんのこと、各列の幅も自動で調整されました!

 

サンプル

サンプルのダウンロード(Infragistics WPF 2016 vol.2 バージョン、C#)

XamDataGrid_PerformAutoSize.zip

(このサンプルは 16.2.20162.2045 バージョンで作成されました。)

XamCalendarの日付の色を変える

XamCalendarの日付の色を土日や祝日は変えたいといったお問い合わせをよくいただきます。

今回はその方法についてご紹介します。

 

Snoopを使って構成要素を確認してみる

まず、Snoopを使ってXamCalendarの日付部分の構成要素を確認してみましょう。

ご覧のように、CalendarDay->Grid->OuterBorder (Border)->InnerBorder (Border)->TextBlockという階層構造になっているのがわかります。

このうち、日付部分の背景色を決めているのはOuterBorder、文字色を決めているのはTextBlockですので、これらのBackgroundプロパティ、Foregroundプロパティを変えれば、曜日に応じた色を設定することができます。

今回は、背景色を変えてみたいと思います。既定のスタイルファイルを再テンプレートします。

 

既定のスタイルファイルを書き換える

既定のスタイルファイルは

C:\Program Files (x86)\Infragistics\2016.2\WPF\DefaultStyles

配下にコントロールごとにインストールされています。

今回はXamCalendarなので、

C:\Program Files (x86)\Infragistics\2016.2\WPF\DefaultStyles\XamCalendar

からテーマにあったxamlファイルをプロジェクトのフォルダーにコピーします。今回は特にテーマを当てないので、generic.shared.xamlをコピーします(※下の図はコピーしてきた後のプロジェクトのフォルダーです)。

このファイルを開き、OuterBorder要素のBackgroundプロパティを書き換えます。曜日に応じた色を設定する必要があるので、親のCalendarDayStartDateプロパティをもとに色を返すIValueConverterクラスのインスタンスをバインドします。

...

<!-- 日付を受け取って色を返すIValueConverter -->
<local:DayToColorConverter x:Key="dayToColorConverter" />

...

<Border x:Name="OuterBorder"
                igPrim:XamlHelper.SnapsToDevicePixels="True"
                HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
                VerticalAlignment="{TemplateBinding VerticalAlignment}"
                BorderThickness="{TemplateBinding BorderThickness}"
                BorderBrush="{TemplateBinding ComputedBorderBrush}"
                CornerRadius="{Binding Path=(igEditors:CalendarBase.Calendar).ResourceProviderResolved[ItemCorderRadius], RelativeSource={RelativeSource TemplatedParent}}">

    <!-- 今回変更している部分 -->
    <Border.Background>
        <Binding
            Converter="{StaticResource dayToColorConverter}"
            RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type igPrim:CalendarDay}}"
            Path="StartDate">
        </Binding>
    </Border.Background>

 

日付から色を返すIValueConverterクラスを用意する

受け取ったDateTimeをもとに、曜日に応じた色を返すIValueConverterを作成します。

今回は、土曜ならLightBlue、日曜ならPink、それ以外ならWhiteを返すようにしています。どのようなロジックを組むかはご自由ですので、ご要件に応じたものをお書きいただけます。

public class DayToColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        DateTime date = (DateTime)value;

        // 土曜の場合
        if (date.DayOfWeek == DayOfWeek.Saturday)
        {
            return Brushes.LightBlue;
        }
        // 日曜の場合
        if (date.DayOfWeek == DayOfWeek.Sunday)
        {
            return Brushes.Pink;
        }
        // それ以外
        return Brushes.White;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

 

MainWindow.xamlでスタイルファイルを読み込むようにする

MainWindow.xaml側です。ResourceDictionaryでスタイルファイルを追加します。

<ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/generic.shared.xaml"/>
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

 

既定のスタイルを再テンプレートする時の注意点

既定のスタイルを再テンプレートする際は、ご利用になっているビルドに合ったものを使用する必要があるという点にご注意ください。

サービスリリースを当てた後やバージョンアップをした後など、弊社製品のバージョンやビルド番号が変わった場合は、改めてスタイルがインストールされているフォルダーから該当スタイルファイルをコピーしてきて、必要な個所を書き換え、再テンプレートしてください。

 

サンプル

サンプルのダウンロード(Infragistics WPF 2016 vol.2 バージョン、C#)

XamCalendar_SetColor.zip

(このサンプルは 16.2.20162.1006 バージョンで作成されました。)

XamComboEditorにIMEを設定する(その2 コードビハインドでイベントを使う)

今回は、XamComboEditorのイベントを使って、コードビハインドでIMEを設定する方法をご紹介します。

 

WPF固有のXamComboEditorも共有XAMLのXamComboEditorも、IMEを設定するにはテキスト編集用で使用しているコントロールに対して設定する必要がある、という点で共通しています。

しかし、使用されているコントロールの種類と生成されるタイミングが違います。

WPF固有のXamComboEditorは、標準のTextBoxを使用し、生成されるタイミングはXamComboEditorが編集モードに入った段階です。

共有XAMLのXamComboEditorは、TextBoxを拡張したSpecializedTextBoxを使用し、生成されるタイミングはXamComboEditorがロードされた段階です。

 

WPF固有のXamComboEditor(名前空間 InfragisticsWPF4.Editors)の場合

WPF固有のXamComboEditorの場合、テキスト編集用で使用しているコントロールはTextBoxで、編集モードに入った段階で生成されます。ですので、XamComboEditorのEditModeStartedイベント(※EditModeStartingイベントではないので注意してください)でTextBoxを取得し、IMEの設定をします。

TextBoxはInfragistics.Windows.Utilities.GetDescendantFromTypeメソッドを使って簡単に取り出すことができます。

private void wpfCombo_EditModeStarted(object sender, Infragistics.Windows.Editors.Events.EditModeStartedEventArgs e)
{
    // 内部で使用されているTextBoxを取得
    TextBox textBox = Utilities.GetDescendantFromType(sender as DependencyObject, typeof(TextBox), true) as TextBox;

    // 内部で使用されているTextBoxを取得できたら
    if (textBox != null)
    {
        InputMethod.SetPreferredImeState(textBox, InputMethodState.Off);
        InputMethod.SetIsInputMethodEnabled(textBox, false);
    }
}

 

共有XAMLのXamComboEditor(名前空間 InfragisticsWPF4.Controls.Editors)の場合

共有XAMLのXamComboEditorの場合、テキスト編集用で使用しているコントロールはSpecializedTextBoxで、XamComboEditorのロード時で生成されます。ですので、ロード後のイベントであれば何でも良いのですが、今回はLoadedイベントでSpecializedTextBoxを取得し、IMEの設定をする例をご紹介します。

SpecializedTextBoxもGetDescendantFromTypeメソッドを使用して取得できます。

private void sharedCombo_Loaded(object sender, RoutedEventArgs e)
{
    // 内部で使用されているSpecializedTextBoxを取得
    SpecializedTextBox spTextBox = Utilities.GetDescendantFromType(sender as DependencyObject, typeof(SpecializedTextBox), true) as SpecializedTextBox;

    // 内部で使用されているSpecializedTextBoxを取得できたら
    if (spTextBox != null)
    {
        InputMethod.SetPreferredImeState(spTextBox, InputMethodState.Off);
        InputMethod.SetIsInputMethodEnabled(spTextBox, false);
    }
}

 

サンプル

サンプルのダウンロード(Infragistics WPF 2016 vol.2 バージョン、C#)

XamComboEditor_IMESettingInCodeBehind.zip

(このサンプルは 16.2.20162.1006 バージョンで作成されました。)

XamComboEditorでIMEを設定する

よく、

「XamComboEditorに対してIMEの設定をしてみましたが設定できません。どうしたらいいでしょうか?」

といったご質問をいただきます。

今回は、XamComboEditorでStyleを使ってIMEを制御する方法をご紹介します。

 

XamComboEditorはWPF固有と共有XAMLと2種類ありますが、どちらもテキスト入力用に別途コントロールを使用しています。IMEの設定はこの入力用コントロールに対して行う必要があります。

 

WPF固有のXamComboEditor(名前空間 InfragisticsWPF4.Editors)の場合

WPF固有のXamComboEditorの場合、標準のTextBoxを入力用コントロールとして使用しています。このTextBoxに対してIMEの設定をします。

今回は、親のXamComboEditorに対してすでにIMEの設定がしてあるという前提で、Styleを使ってXamComboEditorのIMEの設定をTextBoxにバインドする方法をご紹介したいと思います。

<Style TargetType="{x:Type igEditors:XamComboEditor}" x:Key="style1">
    <Style.Resources>
        <Style TargetType="{x:Type TextBox}">
            <Setter
                Property="InputMethod.IsInputMethodEnabled"
                Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type igEditors:XamComboEditor}},Path=(InputMethod.IsInputMethodEnabled)}" />
            <Setter
                Property="InputMethod.PreferredImeState"
                Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type igEditors:XamComboEditor}},Path=(InputMethod.PreferredImeState)}" />
        </Style>
    </Style.Resources>
</Style>

 

共有XAMLのXamComboEditor(名前空間 InfragisticsWPF4.Controls.Editors)の場合

共有XAMLのXamComboEditorの場合、TextBoxを拡張したSpecializedTextBoxというコントロールを使用しています。上の例と同様、このSpecializedTextBoxに対してIMEの設定をします。

<Style TargetType="{x:Type ig:XamComboEditor}" x:Key="style2">
    <Style.Resources>
        <Style TargetType="{x:Type igPrim:SpecializedTextBox}">
            <Setter
                Property="InputMethod.IsInputMethodEnabled"
                Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ig:XamComboEditor}},Path=(InputMethod.IsInputMethodEnabled)}" />
            <Setter
                Property="InputMethod.PreferredImeState"
                Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ig:XamComboEditor}},Path=(InputMethod.PreferredImeState)}" />
        </Style>
    </Style.Resources>
</Style>

 

XamComboEditor側のXAML

XamComboEditorでIMEの設定をし、上のStyleをStyleプロパティに設定します。

<!-- WPF固有のXamComboEditor -->
<igEditors:XamComboEditor
    x:Name="wpfCombo"
    IsEditable="True"
    InputMethod.IsInputMethodEnabled="False"
    InputMethod.PreferredImeState="Off"
    Style="{StaticResource style1}"
    />

<!-- 共有XAMLのXamComboEditor -->
<ig:XamComboEditor
    x:Name="sharedCombo"
    IsEditable="True"
    InputMethod.IsInputMethodEnabled="False"
    InputMethod.PreferredImeState="Off"
    Style="{StaticResource style2}"
    />

 

サンプル

サンプルのダウンロード(Infragistics WPF 2016 vol.2 バージョン、C#)

XamComboEditor_IMESetting.zip

(このサンプルは 16.2.20162.1006 バージョンで作成されました。)

WPF XamDataGrid セルの値に応じてセルの色を変える

XamDataGridでよく頂くお問い合わせとして、セルの値に応じてセルの色を変えたい、というものがあります。今回は、その方法についてご紹介したいと思います。

こちらが今回使用するデータです。Score列が80以上のセルの色(背景色)を薄い青色に変えてみましょう。

 

手順は、

  1. IValueConverterインターフェイスを実装するクラスを作成し、クラスのインスタンスをResourcesに追加する。
  2. CellValuePresenterをターゲットとするStyleを作成し、背景色のプロパティに対して1のインスタンスをバインドし、StyleのインスタンスをResourcesに追加する。
  3. XamDataGridのFieldSettingsのCellValuePresenterStyleを2のスタイルにバインドする。

です。

 

では、順に見ていきましょう。

 

1. IValueConverterインターフェイスを実装するクラスを作成し、クラスのインスタンスをResourcesに追加する。

プロジェクトにクラスを追加し、IValueConverterインターフェースを実装します。今回は、MyScoreCellStyleValueConverterという名前で作成することにします。

Convertメソッドで、引数valueで渡されてきた値をint型に変換し、値が80以上であれば、Colors.LightBlueを返します。それ以外はColors.Whiteを返します。

// MyScoreCellStyleValueConverter.cs
public class MyScoreCellStyleValueConverter : IValueConverter
{
    // ソース(=Score値)からターゲット(=セルの背景色)への変換処理
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // Score値をscoreに代入する
        int score;
        if(Int32.TryParse(value.ToString(), out score)){
            // Score値が80以上の場合
            if(score >= 80)
            {
                // LightBlueを返す
                return Colors.LightBlue;
            }
        }
        // ここまでの条件に当てはまらなかった場合は、Whiteを返す
        return Colors.White;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

MainWindow.xamlで、MyScoreCellStyleValueConverterクラスのインスタンスをResourcesに追加します。KeyはmyScoreCellStyleValueConverterとしておきます。

<!-- MainWindow.xaml -->
<Window.Resources>
    <local:MyScoreCellStyleValueConverter x:Key="myScoreCellStyleValueConverter" />
</Window.Resources>

 

2. CellValuePresenterをターゲットとするStyleを作成し、背景色のプロパティに対して1のインスタンスをバインドし、StyleのインスタンスをResourcesに追加する。

セルのStyleを設定する際に使用するTargetTypeはCellValuePresenterです。背景色のプロパティはBackground、ValueにはSolidColorBrushのインスタンスを設定します。SolidColorBrushのColorプロパティには、1で作成したMyScoreCellStyleValueConverterクラスのインスタンスをConverterとしてバインドし、パスにはDataItem.Scoreを指定します。

ここでのポイントは、

  • TargetTypeはCellValuePresenterである。
  • CellValuePresenterのDataContextはDataRecordクラスである。よって、あるセルの値をPathに指定したい場合は、DataItem.<プロパティ名>やCells[<列名>].Valueでできる。

の2点です。

では、このStyleをResourcesに追加します。KeyはmyScoreCellStyleとしておきます。1とまとめると以下のようなXAMLになります。

<!-- MainWindow.xaml -->
<Window.Resources>
	<local:MyScoreCellStyleValueConverter x:Key="myScoreCellStyleValueConverter" />
    <Style TargetType="{x:Type igDP:CellValuePresenter}" x:Key="myScoreCellStyle">
        <Setter Property="Background">
            <Setter.Value>
                <SolidColorBrush Color="{Binding Path=DataItem.Score, Converter={StaticResource myScoreCellStyleValueConverter}, Mode=OneWay}"/>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

 

3. XamDataGridのFieldSettingsのCellValuePresenterStyleを2のスタイルにバインドする。

2で作成したStyleを列に紐づけるには、FieldSettingsクラスのCellValuePresenterStyleプロパティを使います。

<!-- MainWindow.xaml -->
<igDP:XamDataGrid.FieldLayouts>
    <igDP:FieldLayout>
        <igDP:FieldLayout.Fields>
            <igDP:Field Name="Score">
                <igDP:Field.Settings>
                    <igDP:FieldSettings CellValuePresenterStyle="{StaticResource myScoreCellStyle}">
                    </igDP:FieldSettings>
                </igDP:Field.Settings>
            </igDP:Field>
        </igDP:FieldLayout.Fields>
    </igDP:FieldLayout>
</igDP:XamDataGrid.FieldLayouts>

 

以上で出来上がりです。Score列が80以上のセルが薄い青色になりました!

 

今回のサンプルはこちらからダウンロードできます。

(本サンプルは16.1.20161.2056バージョンで作成されました)