C# XAML でリストデータに対してIndexを付けるコンバーター
作ったは良いが目的が達せられなかったのでメモしておく
チェックボックスを下記の様に並べて、ただ数字を割り振りたいだけの場合、
ViewModel側には「ReactiveCollection<ReactiveProperty<bool>> BoolList{get;}」だけ保持しておけば数字は不要です。
□1 □2 □3 □4
□5 □6 □7 □8
□9 □10 □11 □12
………
………
利点:BoolList の個数を変更すれば自動的にチェックボックスの個数・数字が増減します。
難点:Index(数字)しか出力しないので汎用性が低い。(Boolをクラスにした方が仕様変更には強いよねー)
その他:カラム数は固定ですが、Bindingを使えばViewModel側から指定できるはず。
コンバーターのソース
XAML:
ちなみに、下記みたいな縦順番にするのは無理でした…(BoolとIndex の整合性が取れなくなった)
ので、おとなしくBool ではなく オブジェクト(番号+Bool値)に変更し、Behavior を使って縦順番に変換する処理を作りました。
ここまでくるとBehaviorにする必要さえない気もしますが、列数(Column数)指定をXAMLだけに押し込めるので良いかなぁとかなんとか…
いや、列数はViewModel側に1個持って、Binding したほうが良いと思う…Behavior 作る意味なかったかなぁ…
□1 □5 □9
□2 □6 □10
□3 □7 □11
□4 □8 □12
チェックボックスを下記の様に並べて、ただ数字を割り振りたいだけの場合、
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 □10
□3 □7 □11
□4 □8 □12
/**********************************************************************************
本記事はGooブログから作成者本人が移行しました。
**********************************************************************************/
コメント
コメントを投稿