WPF 列表框中的自定义控件
Custom controls in a WPF ListBox
我创建了一些控件(稍微)扩展了许多 UIElement 的功能以包含 IsError 和 IsCorrect 属性,这些属性用于向用户表示错误情况。
例如,扩展的复选框。
public class EBC_CheckBox : CheckBox
{
public static readonly DependencyProperty IsCorrectProperty = DependencyProperty.Register("IsCorrect", typeof(bool), typeof(EBC_CheckBox), new UIPropertyMetadata(false));
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register("IsError", typeof(bool), typeof(EBC_CheckBox), new UIPropertyMetadata(false));
public EBC_CheckBox() : base()
{
IsError = false;
IsCorrect = false;
}
public bool IsError
{
get { return (bool)GetValue(IsErrorProperty); }
set { SetValue(IsErrorProperty, value); }
}
public bool IsCorrect
{
get { return (bool)GetValue(IsCorrectProperty); }
set { SetValue(IsCorrectProperty, value); }
}
这在 XAML 代码中的样式为:
<Style TargetType="{x:Type local:EBC_CheckBox}">
<Setter Property="Foreground" Value="{StaticResource SBase02}"/>
<Setter Property="Background" Value="{StaticResource SBase0}"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,2,8,2"/>
<Setter Property="BorderBrush" Value="{StaticResource SYellow}"/>
<Setter Property="BorderThickness" Value="2"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{StaticResource SBase01}"/>
<Setter Property="BorderThickness" Value="0"/>
</Trigger>
<Trigger Property="IsError" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource SRed}"/>
</Trigger>
<Trigger Property="IsCorrect" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource SGreen}"/>
</Trigger>
</Style.Triggers>
</Style>
我的问题是,我想将一些复选框添加到 ListBox 中,这在大多数情况下都有效。但是,扩展属性会被忽略,看起来 ListBox 只是将项目作为普通 UIElement 呈现,而不是扩展版本。
<ListBox ItemsSource="{Binding MyObjects}">
<ListBox.ItemTemplate>
<DataTemplate>
<local:EBC_CheckBox Content="{Binding Path=Name}" IsChecked="{Binding Path=IsPresent}" IsError="{Binding Path=IsError}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
如何让对象与扩展属性一起显示在 ListBox 中(设置 IsError 时显示为红色等)?
根据 Damir 的回复,如果我使用数据触发器,我可以设置整个 ListBoxItem 的样式(即设置边框会在整个项目周围设置边框,而不仅仅是更改复选框的颜色)。
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsError}" Value="True">
<Setter Property="BorderBrush" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
是否可以执行类似的操作并重用控件格式,或者我是否需要创建一个带有自定义列表框项的自定义列表框?
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsError}" Value="True">
<Setter Property="local:EBC_CheckBox.IsError" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
进一步编辑:
我发现以下代码有效,它使用了固定的项目列表:
<ListBox HorizontalAlignment="Left" Height="100" Margin="72,383,0,0" Grid.Row="1" VerticalAlignment="Top" Width="100">
<local:EBC_CheckBox Content="Item1" IsCorrect="True"/>
<local:EBC_CheckBox Content="Item2" IsChecked="True"/>
<local:EBC_CheckBox Content="Item3" IsError="True"/>
<local:EBC_CheckBox Content="Item4" />
</ListBox>
列表显示项目,并且根据 EBC_CheckBox 设置正确处理了它们的视觉状态。
如果我更改为绑定项目列表,但事物的视觉方面未正确更新 - Content 和 IsChecked 字段得到正确处理(预期,因为它们位于基本复选框中,但 IsError 字段被忽略)
<ListBox Grid.Column="3" Grid.Row="8" HorizontalAlignment="Left" VerticalAlignment="Top" BorderThickness="0"
ItemsSource="{Binding Things}">
<ListBox.ItemTemplate>
<DataTemplate>
<local:EBC_CheckBox Content="{Binding Path=ThingName}" IsChecked="{Binding Path=IsPresent}" IsError="{Binding Path=IsError}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
我错过了什么???
您必须使用 DataTrigger 而不是简单的 Trigger 才能正确绑定。试试这个:
<DataTrigger Binding="{Binding IsError}" Value="True">
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="FontSize" Value="20"/>
</DataTrigger>
问题解决了,归结为构造函数中依赖属性的设置。这些设置不应该存在,在应用程序中的构造函数覆盖和绑定值中设置这些设置。
另请参阅此 。
我创建了一些控件(稍微)扩展了许多 UIElement 的功能以包含 IsError 和 IsCorrect 属性,这些属性用于向用户表示错误情况。
例如,扩展的复选框。
public class EBC_CheckBox : CheckBox
{
public static readonly DependencyProperty IsCorrectProperty = DependencyProperty.Register("IsCorrect", typeof(bool), typeof(EBC_CheckBox), new UIPropertyMetadata(false));
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register("IsError", typeof(bool), typeof(EBC_CheckBox), new UIPropertyMetadata(false));
public EBC_CheckBox() : base()
{
IsError = false;
IsCorrect = false;
}
public bool IsError
{
get { return (bool)GetValue(IsErrorProperty); }
set { SetValue(IsErrorProperty, value); }
}
public bool IsCorrect
{
get { return (bool)GetValue(IsCorrectProperty); }
set { SetValue(IsCorrectProperty, value); }
}
这在 XAML 代码中的样式为:
<Style TargetType="{x:Type local:EBC_CheckBox}">
<Setter Property="Foreground" Value="{StaticResource SBase02}"/>
<Setter Property="Background" Value="{StaticResource SBase0}"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,2,8,2"/>
<Setter Property="BorderBrush" Value="{StaticResource SYellow}"/>
<Setter Property="BorderThickness" Value="2"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{StaticResource SBase01}"/>
<Setter Property="BorderThickness" Value="0"/>
</Trigger>
<Trigger Property="IsError" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource SRed}"/>
</Trigger>
<Trigger Property="IsCorrect" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource SGreen}"/>
</Trigger>
</Style.Triggers>
</Style>
我的问题是,我想将一些复选框添加到 ListBox 中,这在大多数情况下都有效。但是,扩展属性会被忽略,看起来 ListBox 只是将项目作为普通 UIElement 呈现,而不是扩展版本。
<ListBox ItemsSource="{Binding MyObjects}">
<ListBox.ItemTemplate>
<DataTemplate>
<local:EBC_CheckBox Content="{Binding Path=Name}" IsChecked="{Binding Path=IsPresent}" IsError="{Binding Path=IsError}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
如何让对象与扩展属性一起显示在 ListBox 中(设置 IsError 时显示为红色等)?
根据 Damir 的回复,如果我使用数据触发器,我可以设置整个 ListBoxItem 的样式(即设置边框会在整个项目周围设置边框,而不仅仅是更改复选框的颜色)。
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsError}" Value="True">
<Setter Property="BorderBrush" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
是否可以执行类似的操作并重用控件格式,或者我是否需要创建一个带有自定义列表框项的自定义列表框?
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsError}" Value="True">
<Setter Property="local:EBC_CheckBox.IsError" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
进一步编辑:
我发现以下代码有效,它使用了固定的项目列表:
<ListBox HorizontalAlignment="Left" Height="100" Margin="72,383,0,0" Grid.Row="1" VerticalAlignment="Top" Width="100">
<local:EBC_CheckBox Content="Item1" IsCorrect="True"/>
<local:EBC_CheckBox Content="Item2" IsChecked="True"/>
<local:EBC_CheckBox Content="Item3" IsError="True"/>
<local:EBC_CheckBox Content="Item4" />
</ListBox>
列表显示项目,并且根据 EBC_CheckBox 设置正确处理了它们的视觉状态。
如果我更改为绑定项目列表,但事物的视觉方面未正确更新 - Content 和 IsChecked 字段得到正确处理(预期,因为它们位于基本复选框中,但 IsError 字段被忽略)
<ListBox Grid.Column="3" Grid.Row="8" HorizontalAlignment="Left" VerticalAlignment="Top" BorderThickness="0"
ItemsSource="{Binding Things}">
<ListBox.ItemTemplate>
<DataTemplate>
<local:EBC_CheckBox Content="{Binding Path=ThingName}" IsChecked="{Binding Path=IsPresent}" IsError="{Binding Path=IsError}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
我错过了什么???
您必须使用 DataTrigger 而不是简单的 Trigger 才能正确绑定。试试这个:
<DataTrigger Binding="{Binding IsError}" Value="True">
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="FontSize" Value="20"/>
</DataTrigger>
问题解决了,归结为构造函数中依赖属性的设置。这些设置不应该存在,在应用程序中的构造函数覆盖和绑定值中设置这些设置。
另请参阅此