ItemTemplate中包含绑定的ComboBox的ItemsControl

5

我在使用绑定了ComboBox的ItemTemplate的ItemsControl中绑定集合时遇到了问题。

在我的场景中,我需要为集合中的每个项目“生成”包含文本框和ComboBox的表单,并允许用户更新项目。我可以使用DataGrid来实现,但我希望看到所有行都处于编辑模式,因此我使用了具有自定义ItemTemplate的ItemsControl。

编辑文本框是没有问题的,但当您尝试更改任何ComboBox时,其他行中的所有ComboBox也会更改。 这是一个错误还是一个特性?

谢谢,Ondrej

Window.xaml

<Window x:Class="ComboInItemsControlSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="480" Width="640">
<Window.Resources>

    <CollectionViewSource x:Key="cvsComboSource"
        Source="{Binding Path=AvailableItemTypes}" />

    <DataTemplate x:Key="ItemTemplate">
        <Border BorderBrush="Black" BorderThickness="0.5" Margin="2">
            <Grid Margin="3">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*" />
                    <ColumnDefinition Width="20" />
                    <ColumnDefinition Width="1*" />
                </Grid.ColumnDefinitions>

                <TextBox Grid.Column="0" Text="{Binding Path=ItemValue}" />
                <ComboBox Grid.Column="2"
                          SelectedValue="{Binding Path=ItemType}"
                          ItemsSource="{Binding Source={StaticResource cvsComboSource}}"
                          DisplayMemberPath="Name"
                          SelectedValuePath="Value" />
            </Grid>
        </Border>
    </DataTemplate>

</Window.Resources>
<Grid>

    <ItemsControl ItemsSource="{Binding Path=SampleItems}"
                  ItemTemplate="{StaticResource ItemTemplate}"
                  Margin="10" />

</Grid>

Window.xaml.cs

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();

        DataContext = new ViewModel();
    }
}

public class ViewModel
{
    public ViewModel()
    {
        SampleItems = new List<SampleItem> {
            new SampleItem { ItemValue = "Value 1" },
            new SampleItem { ItemValue = "Value 2" },
            new SampleItem { ItemValue = "Value 3" }
        };

        AvailableItemTypes = new List<SampleItemType> {
            new SampleItemType { Name = "Type 1", Value = 1 },
            new SampleItemType { Name = "Type 2", Value = 2 },
            new SampleItemType { Name = "Type 3", Value = 3 },
            new SampleItemType { Name = "Type 4", Value = 4 }
        };
    }

    public IList<SampleItem> SampleItems { get; private set; }
    public IList<SampleItemType> AvailableItemTypes { get; private set; }
}

public class SampleItem : ObservableObject
{
    private string _itemValue;
    private int _itemType;

    public string ItemValue
    {
        get { return _itemValue; }
        set { _itemValue = value; RaisePropertyChanged("ItemValue"); }
    }
    public int ItemType
    {
        get { return _itemType; }
        set { _itemType = value; RaisePropertyChanged("ItemType"); }
    }
}

public class SampleItemType : ObservableObject
{
    private string _name;
    private int _value;

    public string Name
    {
        get { return _name; }
        set { _name = value; RaisePropertyChanged("Name"); }
    }
    public int Value
    {
        get { return _value; }
        set { _value = value; RaisePropertyChanged("Value"); }
    }
}

public abstract class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged(string propertyName) {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

Picture

here you can see the result on picture


1
根据Rachel的回答,如果我将ComboBox.IsSynchronizedWithCurrentItem设置为“false”,我的解决方案将起作用。 - Ondrej
2个回答

9

我认为问题是你绑定到了 CollectionViewSource,它会跟踪当前项。尝试直接绑定到列表而不是 CollectionViewSource,这样就不会跟踪当前项。

<ComboBox Grid.Column="2"
          SelectedValue="{Binding Path=ItemType}"
          DisplayMemberPath="Name"
          SelectedValuePath="Value"
          ItemsSource="{Binding RelativeSource={
              RelativeSource AncestorType={x:Type ItemsControl}}, 
              Path=DataContext.AvailableItemTypes}" />

好的,我是个傻瓜,你当然是对的 :-) 谢谢你让我开了眼界 :-)。有时候我看不到显而易见的事情。 - Ondrej
+1 对于 ItemsSource 技巧。有没有办法使其强类型化,以便智能感知起作用? - Mike Cole
@MikeCole 我不知道有没有这样的功能。你可能可以使用自定义标记扩展来实现一些功能,但我认为尝试构建它可能会带来更多麻烦,得不偿失 :) - Rachel

1

虽然每一行都有一个组合框,但它们并不被视为独立的。也就是说,它们都使用相同的集合和相同的选定值,因此当一个框中的值发生变化时,所有框中的值都会发生变化。

解决这个问题的最好方法是将SampleItemType集合作为SampleItem模型的属性添加,并将组合框绑定到该属性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接