WPF ComboBox SelectedItem在TabControl Switch上设置为Null

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF ComboBox SelectedItem在TabControl Switch上设置为Null相关的知识,希望对你有一定的参考价值。

我的WPF应用程序中遇到了一个简单的问题,让我在桌面上敲打我的脑袋。我有一个TabControl,其中每个TabItem都是使用类似于此的DataTemplate为ViewModel生成的视图:

<DataTemplate DataType="{x:Type vm:FooViewModel}">
    <vw:FooView/>
</DataTemplate>

FooView包含一个ComboBox:

<ComboBox ItemsSource="{Binding Path=BarList}" DisplayMemberPath="Name" SelectedItem="{Binding Path=SelectedBar}"/>

和FooViewModel包含一个简单的属性:public Bar SelectedBar { get; set; }。我的问题是,当我为我的ComboBox设置值时,更改为另一个选项卡,然后更改回来,ComboBox再次为空。如果我在我的属性的setter上设置断点,我看到当切换到另一个选项卡时该属性被分配给null

根据我的理解,当切换选项卡时,它将从VisualTree中删除 - 但为什么将我的ViewModel属性设置为null?这使得我很难保持持久状态,并且检查value != null似乎不是正确的解决方案。任何人都可以在这种情况下摆脱一些吗?

编辑:设置器断点处的调用堆栈仅显示[外部代码] - 没有提示。

答案

我们遇到了同样的问题。我们找到了一个描述问题的博客文章。看起来它是WPF中的一个错误,并且有一个解决方法:在ItemsSource绑定之前指定SelectedItem绑定,问题应该消失。

博客文章的链接:

http://www.metanous.be/pharcyde/post/Bug-in-WPF-combobox-databinding.aspx

另一答案

您可以使用MVVM框架Catel和catel:TabControl元素,这个问题已经解决了。

另一答案

如果value变为null,则不允许更改ViewModel的属性。

public Bar SelectedBar
{
    get { return barSelected; }
    set { if (value != null) SetProperty(ref barSelected, value); }
}

而已。

另一答案

我的应用程序正在使用avalondock和prims,并有确切的问题。我对BSG有同样的想法,当我们在MVVM应用程序中切换选项卡或文档内容时,控件如listview + box,combobox从VisualTree中删除。我窃听并看到他们的大部分数据被重置为null,例如itemssource,selecteditem,..但是selectedboxitem仍然保持当前值。

一种方法是在模型中,检查它的值是否为null然后返回如下:

 private Employee _selectedEmployee;
 public Employee SelectedEmployee
 {
     get { return _selectedEmployee; }
     set
     {
        if (_selectedEmployee == value || 
            IsAdding ||
            (value == null && Employees.Count > 0))
    {
        return;
    }

    _selectedEmployee = value;
    OnPropertyChanged(() => SelectedEmployee);
} 

但是这种方法只能在第一个绑定级别上解决相当好的问题。我的意思是,如果想将SelectedEmployee.Office绑定到组合框,我们怎么去,如果检查SelectedEmployee模型的propertyChanged事件,那么同样不好。

基本上,我们不希望它的值重置为null,保持其预值。我始终找到了新的解决方案。通过使用附加属性,我为Selector控件创建了KeepSelection a-Pro,bool类型,从而将其所有继承的suck作为listview,combobox ...

public class SelectorBehavior
{

public static bool GetKeepSelection(DependencyObject obj)
{
    return (bool)obj.GetValue(KeepSelectionProperty);
}

public static void SetKeepSelection(DependencyObject obj, bool value)
{
    obj.SetValue(KeepSelectionProperty, value);
}

// Using a DependencyProperty as the backing store for KeepSelection.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty KeepSelectionProperty =
    DependencyProperty.RegisterAttached("KeepSelection", typeof(bool), typeof(SelectorBehavior), 
    new UIPropertyMetadata(false,  new PropertyChangedCallback(onKeepSelectionChanged)));

static void onKeepSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var selector = d as Selector;
    var value = (bool)e.NewValue;
    if (value)
    {
        selector.SelectionChanged += selector_SelectionChanged;
    }
    else
    {
        selector.SelectionChanged -= selector_SelectionChanged;
    }
}

static void selector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var selector = sender as Selector;

    if (e.RemovedItems.Count > 0)
    {
        var deselectedItem = e.RemovedItems[0];
        if (selector.SelectedItem == null)
        {
            selector.SelectedItem = deselectedItem;
            e.Handled = true;
        }
    }
}
}

最后,我在xaml中使用这种方法:

<ComboBox lsControl:SelectorBehavior.KeepSelection="true"  
        ItemsSource="{Binding Offices}" 
        SelectedItem="{Binding SelectedEmployee.Office}" 
        SelectedValuePath="Id" 
        DisplayMemberPath="Name"></ComboBox>

但是,如果选择器的itemssource包含项目,则selecteditem将永远不会为null。它可能会影响某些特殊背景。

希望有所帮助。美好结局! :d

longsam

另一答案

通常,我使用SelectedValue而不是SelectedItem。如果我需要与SelectedValue相关联的对象,那么我将一个包含它的查找字段添加到目标对象(因为我使用T4模板来生成我的视图模型,这往往是在一个部分类中)。如果使用可空属性来存储SelectedValue,那么您将遇到上述问题,但是如果将SelectedValue绑定到不可为空的值(例如int),那么WPF绑定引擎将丢弃null值,因为它不适合目标。

另一答案

编辑:下面的东西工作(我希望......);我开发它是因为我遵循SelectedItems页面上描述的MVVM Lite路线。但是 - 为什么我要依靠SelectedItems?将IsSelected属性添加到我的项目(如图所示here)会自动保留所选项目(在上面的链接中缺少mentioned cavet)。最后,更容易!

Inital Post:好的 - 那是一项工作;我有一个带有SelectionMode =“Extension”的多列ListView,这使得整个事情相当复杂。我的出发点是从工作空间调用tabItems,类似于描述here

  1. 我确保在我的ViewModel中,我知道标签项(工作空间)何时处于活动状态。 (这有点类似于here) - 当然,有人首先需要初始化SelectedWorkspace。 private Int32 _selectedWorkspace; public Int32 SelectedWorkspace { get { return _selectedWorkspace; } set { _selectedWorkspace = value; base.OnPropertyChanged("SelectedWorkspace"); } } protected Int32 _thisWorkspaceIdx = -1; protected Int32 _oldSelectedWorkspace = -1; public void OnSelectedWorkspaceChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "SelectedWorkspace") { if (_oldSelectedWorkspace >= 0) { Workspaces[_oldSelectedWorkpace].OnIsActivatedChanged(false); } Workspaces[SelectedWorkspace].OnIsActivatedChanged(true); _oldSelectedWorkspace = SelectedWorkspace; } } protected bool _isActive = false; protected virtual void OnIsActivatedChanged(bool isActive) { _isActive = isActive; }
  2. 这允许我仅在选项卡项(工作空间)实际处于活动状态时更新ViewModel选定项。因此,即使选项卡项清除ListView.SelectedItems,我的ViewModel选定项列表也会保留。在ViewModel中: if (_isActive) { // ... update ViewModel selected items, referred below as vm.selectedItems }
  3. 最后,当tabItem重新启用时,我连接到'Loaded'事件并恢复了SelectedItems。这是在View的代码隐藏中完成的。 (请注意,虽然我的ListView有多个列,但其中一个用作键,其他列仅供参考.ViewModel selectedItems列表仅保留键。否则,下面的比较会更复杂): private void myList_Loaded(object sender, RoutedEventArgs e) { myViewModel vm = DataContext as myViewModel; if (vm.selectedItems.Count > 0) { foreach (string myKey in vm.selectedItems) { foreach (var item in myList.Items) { MyViewModel.MyItem i = item as MyViewModel.MyItem; if (i.Key == myKey) { myList.SelectedItems.Add(item); } } } } }
另一答案

如果你在WPF中起诉异步选择然后从ComboBox中删除它IsSynchronizedWithCurrentItem =“True”,请参阅有关IsSynchronizedWithCurrentItem的文档:

<ComboBox 
    Name="tmpName" 
    Grid.Row="10" 
    Width="250" 
    Text="Best Match Position List" 
    HorizontalAlignment="Left" 
    Margin="14,0,0,0"

    SelectedItem="{Binding Path=selectedSurceList,Mode=TwoWay}"
    ItemsSource="{Binding Path=abcList}"  
    DisplayMemberPath="Name"
    SelectedValuePath="Code"
    IsEnabled="{Binding ElementName=UserBestMatchYesRadioBtn,Path=IsChecked}">
</ComboBox>

还要注意绑定首先使用SelectedItem然后使用ItemsSource

ref:http://social.msdn.microsoft.com/Forums/vstudio/en-US/fb8a8ad2-83c1-43df-b3c9-61353979d3d7/comboboxselectedvalue-is-lost-when-itemssource-is-updated?forum=wpf

http://social.msdn.microsoft.com/Forums/en-US/c9e62ad7-926e-4612-8b0c-cc75fbd160fd/bug-in-wpf-combobox-data-binding

我用上面的方法解决了我的问题

另一答案

我曾经遇到过类似的问题。似乎组合框在VisibilityChanged事件中丢失了所选项。 Workarround是在发生之前清除绑定,并在返回时重置它。您也可以尝试将Binding设置为Mode = TwoWay

希望这会有所帮助

以上是关于WPF ComboBox SelectedItem在TabControl Switch上设置为Null的主要内容,如果未能解决你的问题,请参考以下文章

WPF combobox selectedItem的问题

WPF:为啥我的 ComboBox SelectedItem 不显示?

WPF MVVM ComboBox SelectedItem 或 SelectedValue 不起作用

WPF中ComboBox控件的SelectedItem和SelectedValue的MVVM绑定

WPF Datagrid Combobox SelectedItem 未正确绑定到 Powershell 对象

WPF ComboBox SelectedItem 在 TabControl 开关上设置为 Null