WPF ComboBox SelectedItem

时间:2010-01-28 17:59:16

标签: wpf mvvm combobox selecteditem

好的,我已经和WPF合作了一段时间,但我需要一些帮助。

我有一个ComboBox如下:

<TabControl>
    <TabItem Header="1">
        <ComboBox ItemsSource="{Binding MyList}" SelectedItem="{Binding MyListSelection}"/>
    </TabItem>
    <TabItem Header="2"/>
</TabControl>

每当我离开标签1然后再回到它时,选择就会被删除。我认为这样做的原因是控件在超出范围然后重新进入时会被销毁。但是在过程中,SelectedItem变为null,这不是用户想要的,因为UI是一个事件的生命周期。

所以我想知道最佳路线是什么?我正在使用MVVM构建这个应用程序,所以我可以忽略我的ViewModel中的MyListSelection属性的set调用,但是我在整个地方都有ComboBox,并且不喜欢修改我的ViewModel,因为我认为它是WPF的一个bug。

我可以继承WPF ComboBox,但是没有SelectedItemChanging事件我只能在SelectedItem更改时添加处理程序。

有什么想法吗?

更新:

好吧,在我的头撞墙后,我发现为什么我的问题无法复制。如果列表项类型由于某种原因是一个类,则由WPF将SelectedItem设置为null,但如果它是值类型则不会。

这是我的测试类(VMBase只是一个实现INotifyPropertyChanged的抽象类):

public class TestListViewModel : VMBase
{
    public TestListViewModel()
    {
        TestList = new List<TestViewModel>();
        for (int i = 0; i < 10; i++)
        {
            TestList.Add(new TestViewModel(i.ToString()));
        }
    }

    public List<TestViewModel> TestList { get; set; }

    TestViewModel _SelectedTest;
    public TestViewModel SelectedTest
    {
        get { return _SelectedTest; }
        set
        {
            _SelectedTest = value;
            OnPropertyChanged("SelectedTest");
        }
    }
}

public class TestViewModel : VMBase
{
  public string Name {get;set;}
}

因此,当我将TestList更改为int类型并在选项卡之间来回切换时,SelectedItem保持不变。但是当它是类型TestViewModel时,当tabitem失焦时,SelectedTest被设置为null。

发生了什么事?

7 个答案:

答案 0 :(得分:10)

我遇到了同样的问题,直到现在我无法确定问题所在。我在具有相同操作系统,.Net版本和硬件规格的4台不同机器上进行了测试,并且可以在其中两个机器中重现这个问题,而在其他机器中工作得很好。 我能找到适合我的解决方法是在ItemsSource之前定义SelectedItem绑定。奇怪的是,如果我遵循这种模式,一切都按预期工作。 也就是说,你只需要做以下事情:

<Window x:Class="ComboBoxInTabItemSpike.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <TabControl>
            <TabItem Header="1">
                <ComboBox SelectedItem="{Binding MySelect}" ItemsSource="{Binding MyList}"/>
            </TabItem>
            <TabItem Header="2"/>
        </TabControl>
        <TextBlock Text="{Binding MySelect}"/>
    </StackPanel>
</Window>

答案 1 :(得分:0)

OP改变后编辑。 嗨,何塞,我无法再现你提到的错误。因此,关于控制被破坏的假设是错误的。即使现在使用引用类型,Combobox的行为与下面的代码一样正常。更改TabItems时,必须启用其他一些代码。

<Window x:Class="ComboBoxInTabItemSpike.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <TabControl>
            <TabItem Header="1">
                <ComboBox ItemsSource="{Binding MyList}"
                          SelectedItem="{Binding MySelect}"/>
            </TabItem>
            <TabItem Header="2"/>
        </TabControl>
        <TextBlock Text="{Binding MySelect}"/>
    </StackPanel>
</Window>

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;

namespace ComboBoxInTabItemSpike
{
    public partial class Window1 : Window, INotifyPropertyChanged
    {
        public Window1()
        {
            InitializeComponent();
            MyList=new ObservableCollection<TestObject>(
                new[]{new TestObject("1"),new TestObject("2"),new TestObject("3") });
            DataContext = this;
        }

        public ObservableCollection<TestObject> MyList { get; set; }

        private TestObject mySelect;
        public TestObject MySelect
        {
            get { return mySelect; }
            set{ mySelect = value;
            if(PropertyChanged!=null)
                PropertyChanged(this,new PropertyChangedEventArgs("MySelect"));} 
        }

        public TestObject MySelectedItem
        {
            get { return (TestObject)GetValue(MySelectedItemProperty); }
            set { SetValue(MySelectedItemProperty, value); }
        }

        public static readonly DependencyProperty MySelectedItemProperty =
            DependencyProperty.Register("MySelectedItem",
                                typeof(TestObject),
                                typeof(Window1),
                                new UIPropertyMetadata(null));

        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class TestObject
    {
        public string Name { get; set; }

        public TestObject(string name)
        {
            Name = name;
        }

        public override string ToString()
        {
            return Name;
        }
    }
}

答案 2 :(得分:0)

我建议检查绑定。如果您的应用中的任何其他内容正在更改所选项目或项目来源,那么您的绑定将会中断。您还可以在输出窗口中查看Visual Studio以查看是否存在任何错误。

答案 3 :(得分:0)

我认为你可能缺少的是SelectedItem上的TwoWay绑定。当你绑定包含MyList(绑定的ItemsSource)的ViewModel类和MyListSelection(你的Case中的Bond到SelectedItem)时,即使你去了不同的标签,它们也总会有这些信息。因此,当您返回此Tab时,MyListSelection将再次绑定回ComboBoc.SelectedItem,您将会很好。试试这个,让我知道。

答案 4 :(得分:0)

我认为这可以通过简单的空检查来解决。

public TestViewModel SelectedTest
{
    get { return _SelectedTest; }
    set
    {
        if(value != null)
            _SelectedTest = value;
        OnPropertyChanged("SelectedTest");
    }
}

这是因为ComboBox在回收时有重置其SelectedIndex的倾向。这个简单的空检查将强制它重新绑定到最后一个有效项。

答案 5 :(得分:0)

我的列表中的引用类型遇到了完全相同的问题。解决方案是在TestViewModel中重写Equals(),以便WPF能够在对象之间执行值相等性检查(而不是引用检查),以确定哪个是SelectedItem。我碰巧有一个ID字段,它实际上是TestViewModel的识别功能。

答案 6 :(得分:0)

组合框的这种行为应该由编译器以比它更好的方式实现... IE编译器应该检查并查看ItemsSource的类型和SelectedItem属性的类型引用值绑定将永远返回一个可比较的值

它应该警告您可以考虑重写Equals()和GetHashCode()方法......

今天在这上面浪费了很多时间!!

相关问题