ComboBox与IEnumerable <brush>一起作为ItemsSource和SelectedItem异常</brush>

时间:2009-10-20 15:27:52

标签: c# wpf exception mvvm combobox

我在使用IEnumerable<Brush>作为ItemsSource的ComboBox时遇到此问题;问题在于我(以编程方式)尝试设置SelectedItem。以下是描述问题的代码:

private readonly List<Brush> colors_;
private Brush white_;

ViewModelConstructor()
{
    colors_ = (from p in brushes_type.GetProperties()
               select (Brush)converter.ConvertFromString(p.Name)).ToList();

    white_ = colors_.Single(b => b.ToString() == "#FFFFFFFF");
}

public IEnumerable<Brush> Colors
{
    get { return colors_; }
}

public Brush White
{
    get { return white_; }
    set
    {
        if (white_ != value)
            white_ = value;
    }
}

这是xaml代码:

<ComboBox ItemsSource="{Binding Path=Colors}"
          SelectedItem="{Binding Path=White}">

    <ComboBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">

                <Border BorderThickness="1"
                        BorderBrush="Black"
                        Width="20"
                        Height="12"
                        SnapsToDevicePixels="True"
                        Margin="0,0,4,0">

                    <Border Background="{Binding}"/>

                </Border>

                <TextBlock Text="{Binding}"/>

            </StackPanel>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

在调用White属性后,我得到一个异常:无法在对象'#FFFFFFFF'上设置属性,因为它处于只读状态。如果我将White(white_)留空,一切正常。

2 个答案:

答案 0 :(得分:3)

使用反射器我已经找到了问题出现的地方。在Selector.ItemSetIsSelected内,它需要新的SelectedItem并执行以下操作:

  • 如果元素的容器DependencyObject,则会将容器上的IsSelectedProperty设置为true
  • 否则,如果元素DependencyObject,则会将元素上的IsSelectedProperty设置为true

第二部分是失败发挥作用的地方,您选择的Brush个对象是只读的。由于在这种情况下Selector.ItemSetIsSelected有点破坏,因此您有两种选择。

选项1 ,您只需在从Converter返回的Brush对象上调用.Clone()。

colors_ = (from p in typeof(Brushes).GetProperties()
    select ((Brush)converter.ConvertFromString(p.Name)).Clone()).ToList();

编辑:您应该使用选项1 ...选项2是解决问题的长途方法

选项2 ,您可以将Brush对象包装成另外一个对象:

public class BrushWrapper
{
    public Brush Brush { get; set; }
}

然后更新数据模板路径:

<Border Background="{Binding Path=Brush}" />

<TextBlock Text="{Binding Path=Brush}" />

最后,您更新了ViewModel

private readonly List<BrushWrapper> colors_;
private BrushWrapper white_;

public ColorViewModel()
{
    colors_ = (from p in typeof(Brushes).GetProperties()
               select new BrushWrapper {
                   Brush = (Brush)converter.ConvertFromString(p.Name)
               }).ToList();

    white_ = colors_.Single(b => b.Brush.ToString() == "#FFFFFFFF");
}

public List<BrushWrapper> Colors
{
    get { return colors_; }
}

public BrushWrapper White
{
    get { return white_; }
    set
    {
        if (white_ != value)
            white_ = value;
    }
}

答案 1 :(得分:0)

这里只是一个黑暗的镜头(目前无法尝试),但是如何绑定SelectedValue而不是SelectedItem?