いつもどこかでデスマーチ♪

不定期に、私の日常を書き込みしていきます。

C# XAML でリストデータに対してIndexを付けるコンバーター

2024年10月03日 11時01分16秒 | メモ
作ったは良いが目的が達せられなかったのでメモしておく

チェックボックスを下記の様に並べて、ただ数字を割り振りたいだけの場合、
ViewModel側には「ReactiveCollection<ReactiveProperty<bool>> BoolList{get;}」だけ保持しておけば数字は不要です。
□1 □2 □3 □4
□5 □6 □7 □8
□9 □10 □11 □12
………
………

利点:BoolList の個数を変更すれば自動的にチェックボックスの個数・数字が増減します。
難点:Index(数字)しか出力しないので汎用性が低い。(Boolをクラスにした方が仕様変更には強いよねー)
その他:カラム数は固定ですが、Bindingを使えばViewModel側から指定できるはず。




コンバーターのソース
/// <summary>
/// ItemsControl で利用されるデータのIndex値を取得します。
/// </summary>
public class ItemsIndexConverter : IMultiValueConverter
{
    /// <summary>
    /// ItemsControl に対し、Index値を取得します
    /// </summary>
    /// <param name="values">表示元の値</param>
    /// <param name="targetType">データ型</param>
    /// <param name="parameter">画面からのパラメータ</param>
    /// <param name="culture">国情報(必ずen-USが来ます)</param>
    /// <returns>表示するデータ</returns>
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values[1] is ItemsControl itemsControl)
        {
            int value = 0;
            if (int.TryParse(parameter?.ToString(), out int result))
            {
                value = result;
            }

            // アイテムのインデックスを取得
            return (itemsControl.Items.IndexOf(values[0]) + value).ToString();
        }

        return -1; // エラー時のデフォルト値
    }

    /// <summary>
    /// 画面データから内部データに変換します
    /// </summary>
    /// <param name="value">表示元の値</param>
    /// <param name="targetTypes">データ型</param>
    /// <param name="parameter">画面からのパラメータ</param>
    /// <param name="culture">国情報(必ずen-USが来ます)</param>
    /// <returns>取得データ</returns>
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}


XAML:
<Grid Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center" Margin="10,0,5,0">
    <!-- チェックボックスを均等割り付けで動的に配置 -->
    <ItemsControl ItemsSource="{Binding BoolList}">
        <ItemsControl.ItemsPanel>
            <!-- Gridの中に均等割り付けで配置する -->
            <ItemsPanelTemplate>
                <!-- 必要に応じてColumns数を調整 -->
                <UniformGrid Columns="4" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.ItemTemplate>
            <!-- インデックス表示用のテンプレート -->
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <!-- MultiBindingでインデックスを取得して表示 -->
                    <CheckBox Foreground="Black" VerticalAlignment="Center" Margin="5,5,15,5" Focusable="False" 
                              IsChecked="{Binding Value}">
                        <CheckBox.Content>
                            <!-- 1から始めたいのでConverterParameterに1を設定する -->
                            <MultiBinding Converter="{StaticResource IndexConverter}" ConverterParameter="1">
                                <!-- アイテム自身をバインド -->
                                <Binding />
                                <!-- ItemsControl全体をバインド -->
                                <Binding RelativeSource="{RelativeSource" AncestorType="ItemsControl}"/>
                            </MultiBinding>
                        </CheckBox.Content>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>




ちなみに、下記みたいな縦順番にするのは無理でした…(BoolとIndex の整合性が取れなくなった)
ので、おとなしくBool ではなく オブジェクト(番号+Bool値)に変更し、Behavior を使って縦順番に変換する処理を作りました。
ここまでくるとBehaviorにする必要さえない気もしますが、列数(Column数)指定をXAMLだけに押し込めるので良いかなぁとかなんとか…
いや、列数はViewModel側に1個持って、Binding したほうが良いと思う…Behavior 作る意味なかったかなぁ…
□1 □5 □9
□2 □6 …
□3 □7 …
□4 □8 …
コメント    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« Chat GTP …お前ってやつは… ... | トップ | 最近良く忘れるので… »

コメントを投稿

ブログ作成者から承認されるまでコメントは反映されません。

メモ」カテゴリの最新記事