【问题标题】:Displaying customised Item in ItemsControl在 ItemsControl 中显示自定义项目
【发布时间】:2015-08-10 02:04:50
【问题描述】:

我创建了一个(稍微)扩展的 Checkbox,它具有 IsError 属性(主要用于在不满足某些条件时将复选框的颜色更改为红色),如下所示:

public class MyCheckBox : CheckBox
{
    public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register("IsError", typeof(bool), typeof(MyCheckBox), new UIPropertyMetadata(false));

    public MyCheckBox() : base()
    {
        IsError = false;
        IsCorrect = false;
    }

    public bool IsError
    {
        get { return (bool)GetValue(IsErrorProperty); }
        set { SetValue(IsErrorProperty, value); }
    }
}

此控件与以下样式相关联:

<Style TargetType="{x:Type local:MyCheckBox}">
    <Setter Property="FontSize" Value="14"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Margin" Value="0,2,8,2"/>
    <Setter Property="BorderBrush" Value="Yellow"/>
    <Setter Property="BorderThickness" Value="2"/>
    <Style.Triggers>
        <Trigger Property="IsEnabled" Value="False">
            <Setter Property="Foreground" Value="LightGray"/>
            <Setter Property="BorderThickness" Value="0"/>
        </Trigger>
        <Trigger Property="IsError" Value="True">
            <Setter Property="BorderBrush" Value="Red"/>
        </Trigger>
    </Style.Triggers>
</Style>

一切都很好,如果我创建这些复选框之一,它会正确响应 IsError 绑定。

我遇到的问题是将这些放在 ItemsControl 中时。如果我创建一个非常基本的项目控件并手动设置值,那么它就可以工作 - 显示项目列表并且 IsError 和 IsChecked 属性按预期运行。

<ItemsControl Grid.Column="3" Grid.Row="8" HorizontalAlignment="Left" VerticalAlignment="Top" BorderThickness="0">
    <local:MyCheckBox Content="Item1"/>
    <local:MyCheckBox Content="Item2" IsChecked="True"/>
    <local:MyCheckBox Content="Item3" IsError="True"/>
    <local:MyCheckBox Content="Item4" IsChecked="True" IsError="True"/>
</ItemsControl>

但是,如果我对项目列表使用绑定,则 Content 和 IsChecked 属性按预期工作,但 IsError 属性被完全忽略,我无法将边框更改为红色。

<ItemsControl Grid.Column="3" Grid.Row="8" HorizontalAlignment="Left" VerticalAlignment="Top" BorderThickness="0">
              ItemsSource="{Binding MyThings}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <local:MyCheckBox Content="{Binding Path=ColorName}" IsChecked="{Binding Path=IsPresent}" IsError="{Binding Path=IsError}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

我知道 IsError 绑定值是正确的(我通过包含一个绑定到显示正确真/假信息的相同值的标签进行测试)但我不知道如何让自定义复选框正确显示;就好像显示的项目使用的是标准复选框而不是自定义版本。

作为参考,控件绑定的项目列表如下:

public class Thing : INotifyPropertyChanged
{
    #region INotifyPropertyChanged
    protected void RaisePropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    #endregion

    private string colorName;
    public string ColorName 
    {
        get { return colorName; }
        set { colorName = value; RaisePropertyChanged("ColorName"); } 
    }

    private bool isPresent;
    public bool IsPresent
    {
        get { return isPresent; }
        set { isPresent = value; RaisePropertyChanged("IsPresent"); }
    }

    private bool isError;
    public bool IsError
    {
        get { return isError; }
        set { isError = value; RaisePropertyChanged("IsError"); } 
    }

    public CastorClip(string colorName)
    {
        ColorName = colorName;
        IsPresent = false;
        IsError = false;
    }
}

private ObservableCollection<Thing> myThings = new ObservableCollection<Thing>();
public ObservableCollection<Thing> MyThings
{
    get { return myThings; }
    set { myThings = value; RaisePropertyChanged("MyThings"); }
}

我错过了什么?我怎样才能做到这一点?

【问题讨论】:

    标签: c# wpf itemscontrol


    【解决方案1】:

    事实证明这是自定义复选框的构造函数中的一个问题,其中 IsError 属性被设置为覆盖绑定表达式。我也会在这里列出其他可能性,以便其他确实陷入 WPF 这些常见陷阱的人可以立即检查它们。

    属性IsError默认不绑定两种方式,改一下:

    new UIPropertyMetadata(false)
    

    到:

    new FrameworkPropertyMetadata {
        BindsTwoWayByDefault = true,
        DefaultValue = false
    }
    

    另外,将此添加到复选框的静态构造函数中,以便它会寻找特定于您的复选框的默认样式:

    static MyCheckBox ()
    {
        DefaultStyleKeyProperty.OverrideMetadata (typeof (MyCheckBox), new FrameworkPropertyMetadata (typeof (MyCheckBox)));
    }
    

    请务必检查资源是如何添加到您的应用中的。

    【讨论】:

    • 我已尝试将 IsError 更改为默认使用上述两种方式绑定,并在 XAML 中将 Mode 更改为 TwoWay,但没有任何变化,该值正在传递给 ItemsControl(我可以通过使用标签查看值),但 MyCheckBox 上的触发器似乎没有被调用。
    • 是的,它没有将自定义样式识别为默认样式,另外,请务必检查样式是如何添加到应用程序资源中的。
    • 如果我添加静态构造函数,那么 CheckBoxes 根本不会显示。我发现如果我从链接到复选框的事件处理程序中更改 IsError 值,那么错误事件确实会发生(我直接从 Checked 事件设置 IsError 值,并在 Unchecked 事件中清除),但是如果我使从视图模型代码更改为 IsError 然后什么也没有发生。
    • 这实际上是一个好兆头,当您添加静态构造函数时,您会强制系统查找特定于您的控件的样式,如果找不到,则根本不会显示任何内容...这就是为什么在它看起来像一个普通复选框之前,它没有找到您的样式,因此它使用默认样式。看起来您没有将其合并到 App.xaml 中。发布您定义样式的方式和位置
    • MyCheckBox 样式包含在上面,它在应用程序的 Windows.Resources 部分中定义,但我尝试将其移至 Application.Resources 并没有区别。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 2012-02-22
    • 1970-01-01
    相关资源
    最近更新 更多