开发者

Set ComboBox SelectedItem to dataobject not present in ItemSource

I have a combobox whose SelectedItem and ItemSource properties are bound to the viewmodel. The objects in the ItemSource are time sensitive in that the objects expire and I can only set active items in the collection to the ItemSource. Now at a certain p开发者_运维知识库oint, the selectedItem object maynot be in the ItemSource. I think the normal behaviour of the ItemSource is to only allow objects to be selected from the ItemSource Collection but in this case I do want to select an object which is no longer in the ItemSource. How can I implement this behaviour? I will post some code here to support my problem.

Window.xaml

 <Window x:Class="ExpiredSelectedItem.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <ComboBox Height="23" 
              HorizontalAlignment="Left" 
              Margin="184,68,0,0" 
              Name="comboBox1" 
              VerticalAlignment="Top" 
              Width="120" 
              ItemsSource="{Binding CustomList}"
              SelectedItem="{Binding ActiveItem}"
              SelectedValue="Code"
              SelectedValuePath="{Binding ActiveItem.Code}"
              DisplayMemberPath="Code"
              />
</Grid>

Window.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ExpiredSelectedItem
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>

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

        CustomList = new List<DomainObject>();

        CustomList.AddRange(new DomainObject[] {
            new DomainObject() { Code = "A", IsActive =true},
            new DomainObject() { Code ="B", IsActive = true},
            new DomainObject() { Code = "C", IsActive =true},
        });

        ActiveItem = new DomainObject() { Code = "D", IsActive = false };

        this.DataContext = this;
    }


    public List<DomainObject> CustomList { get; set; }

    public DomainObject ActiveItem { get; set; }
}

public class DomainObject
{
    public string Code { get; set; }
    public bool IsActive { get; set; }

}

}

Even though I select the code D in the code-behind, when the combobox loads the first item (A) is selected. Expected behaviour was that "D" should have been selected in the textbox but no items should be when the dropdown is opened.


I don't know if this plays any role, but it sure looks suspicious. Try removing it:

<ComboBox ... SelectedValue="Code" ...


To keep the selected item when it is not in the list you can to do the following:

  • Prevent the ActiveItem from getting set to NULL; see: if (value != null)
  • Clear the ComboBox; see: comboBox1.SelectedIndex = -1;
  • Implement INotifyPropertyChanged (which you probably already do)

These changes might cause your code more harm than good, but hopefully this gets you started.

Here is the code-behind:

using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;

namespace ComboBoxSelectedItem
{
  public partial class MainWindow : Window, INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;
    void Notify(string propName)
    {
      if (PropertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs(propName));
      }
    }

    public MainWindow()
    {
      InitializeComponent();

      CustomList = new List<DomainObject>();

      CustomList.AddRange(new DomainObject[] {
        new DomainObject() { Code = "A", IsActive =true},
        new DomainObject() { Code ="B", IsActive = true},
        new DomainObject() { Code = "C", IsActive =true},
        });

      this.DataContext = this;
    }

    public List<DomainObject> CustomList { get; set; }

    private DomainObject _activeItem = new DomainObject() { Code = "D", IsActive = false };
    public DomainObject ActiveItem 
    {
      get { return _activeItem; }
      set
      {
        if (value != null)
        {
          _activeItem = value;
        }

        Notify("ActiveItem");
      }
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
      ActiveItem = new DomainObject() { Code = "D", IsActive = false };
      comboBox1.SelectedIndex = -1;
    }
  }
}

Here is the XAML:

<Window x:Class="ComboBoxSelectedItem.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
  <Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <ComboBox 
        Grid.Row="0"
        Height="23" 
        HorizontalAlignment="Left" 
        Name="comboBox1" 
        VerticalAlignment="Top" 
        Width="120" 
        ItemsSource="{Binding CustomList}"
        SelectedItem="{Binding ActiveItem}"
        DisplayMemberPath="Code"/>
    <TextBox 
        Grid.Row="1"
        Text="{Binding Path=ActiveItem.Code, Mode=TwoWay}"/>
    <Button 
        Grid.Row="2" 
        Content="D" 
        Click="Button_Click"/>
  </Grid>
</Window>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜