将 ItemsControl 绑定到单个模型上的各个属性?
Bind an ItemsControl to individual properties on a single model?
我有一个具有许多 bool
属性的模型,例如:-
public BasicPreferences
{
public bool ShowLegend {get;set;}
public bool ShowLabels {get;set;}
public bool ShowTooltips {get;set;}
}
(简化 - 真正的 class 实现 INotifyPropertyChanged)。
我目前将它们呈现为网格中的一系列复选框,例如:-
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<!-- First option -->
<TextBlock Grid.Column="0" Grid.Row="0" Text="Show legend?" />
<CheckBox Grid.Column="1" Grid.Row="0" IsChecked="{Binding Preferences.ShowLegend" />
<!-- Second option -->
<TextBlock Grid.Column="0" Grid.Row="1" Text="Show labels?" />
<CheckBox etc...
</Grid>
(再次简化以删除样式等)
我计划创建更多模型 classes 继承上述 class 并添加 bool
它们自己的属性,例如
public AdvancedPreferences : BasicPreferences
{
public bool IsFooEnabled {get;set;}
..etc..
}
很明显,我需要找到 "hardcoded" XAML 网格的替代方案,所以有什么方法可以利用数据绑定来显示(比如)ItemsControl 中的选项,同时保持模型原样?我意识到标准的 WPF 解决方案是将选项公开为可观察的集合,但我想保持模型原样,将选项作为单独的属性(在应用程序代码的其他地方引用)。
DataForm 控件可以满足您的需要。它给出了模型的视觉表示。您需要将模型绑定到控件,控件将根据 属性 类型呈现相应的 UI 元素。像字符串类型属性的 TextBox,布尔类型属性的复选框等等。它是高度可定制的。
通常的做法是通过转换器。转换器获取您的 BasicPreferences
class,并使用反射生成您的属性的 ObservableCollection<object>
(绑定所需的任何内容)。后面如果要区分各种属性类型,可以在ItemsControl
.
中使用DataTemplate
这也是一个示例实现:https://wpftoolkit.codeplex.com/wikipage?title=PropertyGrid
这是一个可能的解决方案:
在您的视图模型中,创建对象的可观察集合:
public ObservableCollection<object> Preferences { get; set; }
然后,将您的偏好添加到这个可观察的集合中。
创建一个转换器,它将测试首选项列表中对象的类型,并return基于对象类型的可见性:
public class IsAdvancedPreferencesConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Type t = value.GetType();
if (t == typeof(AdvancedPreferences))
return Visibility.Visible;
else return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
根据您的看法,在 window 资源中创建转换器:
<Window.Resources>
<ViewModels:IsAdvancedPreferencesConverter x:Key="IsAdvancedPreferencesConverter"/>
</Window.Resources>
现在,使用以下 ItemsControl:
<ItemsControl ItemsSource="{Binding Preferences}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<CheckBox Grid.Row="0" IsChecked="{Binding ShowLegend}" Content="Show Legend?"/>
<CheckBox Grid.Row="1" IsChecked="{Binding ShowLabels}" Content="Show Labels?"/>
<CheckBox Grid.Row="2" IsChecked="{Binding ShowTooltips}" Content="Show Tooltips?"/>
<Grid Grid.Row="3" Visibility="{Binding Converter={StaticResource IsAdvancedPreferencesConverter}}">
<Grid.RowDefinitions>
<RowDefinition/>
...
</Grid.RowDefinitions>
<CheckBox Grid.Row="0" IsChecked="{Binding IsFooEnabled}" Content="Is Foo Enabled?"/>
...
</Grid>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
在这种情况下,如果列表中项目的类型是高级首选项,则包含高级首选项复选框的网格将可见。
我有一个具有许多 bool
属性的模型,例如:-
public BasicPreferences
{
public bool ShowLegend {get;set;}
public bool ShowLabels {get;set;}
public bool ShowTooltips {get;set;}
}
(简化 - 真正的 class 实现 INotifyPropertyChanged)。
我目前将它们呈现为网格中的一系列复选框,例如:-
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<!-- First option -->
<TextBlock Grid.Column="0" Grid.Row="0" Text="Show legend?" />
<CheckBox Grid.Column="1" Grid.Row="0" IsChecked="{Binding Preferences.ShowLegend" />
<!-- Second option -->
<TextBlock Grid.Column="0" Grid.Row="1" Text="Show labels?" />
<CheckBox etc...
</Grid>
(再次简化以删除样式等)
我计划创建更多模型 classes 继承上述 class 并添加 bool
它们自己的属性,例如
public AdvancedPreferences : BasicPreferences
{
public bool IsFooEnabled {get;set;}
..etc..
}
很明显,我需要找到 "hardcoded" XAML 网格的替代方案,所以有什么方法可以利用数据绑定来显示(比如)ItemsControl 中的选项,同时保持模型原样?我意识到标准的 WPF 解决方案是将选项公开为可观察的集合,但我想保持模型原样,将选项作为单独的属性(在应用程序代码的其他地方引用)。
DataForm 控件可以满足您的需要。它给出了模型的视觉表示。您需要将模型绑定到控件,控件将根据 属性 类型呈现相应的 UI 元素。像字符串类型属性的 TextBox,布尔类型属性的复选框等等。它是高度可定制的。
通常的做法是通过转换器。转换器获取您的 BasicPreferences
class,并使用反射生成您的属性的 ObservableCollection<object>
(绑定所需的任何内容)。后面如果要区分各种属性类型,可以在ItemsControl
.
DataTemplate
这也是一个示例实现:https://wpftoolkit.codeplex.com/wikipage?title=PropertyGrid
这是一个可能的解决方案:
在您的视图模型中,创建对象的可观察集合:
public ObservableCollection<object> Preferences { get; set; }
然后,将您的偏好添加到这个可观察的集合中。
创建一个转换器,它将测试首选项列表中对象的类型,并return基于对象类型的可见性:
public class IsAdvancedPreferencesConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Type t = value.GetType();
if (t == typeof(AdvancedPreferences))
return Visibility.Visible;
else return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
根据您的看法,在 window 资源中创建转换器:
<Window.Resources>
<ViewModels:IsAdvancedPreferencesConverter x:Key="IsAdvancedPreferencesConverter"/>
</Window.Resources>
现在,使用以下 ItemsControl:
<ItemsControl ItemsSource="{Binding Preferences}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<CheckBox Grid.Row="0" IsChecked="{Binding ShowLegend}" Content="Show Legend?"/>
<CheckBox Grid.Row="1" IsChecked="{Binding ShowLabels}" Content="Show Labels?"/>
<CheckBox Grid.Row="2" IsChecked="{Binding ShowTooltips}" Content="Show Tooltips?"/>
<Grid Grid.Row="3" Visibility="{Binding Converter={StaticResource IsAdvancedPreferencesConverter}}">
<Grid.RowDefinitions>
<RowDefinition/>
...
</Grid.RowDefinitions>
<CheckBox Grid.Row="0" IsChecked="{Binding IsFooEnabled}" Content="Is Foo Enabled?"/>
...
</Grid>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
在这种情况下,如果列表中项目的类型是高级首选项,则包含高级首选项复选框的网格将可见。