WPF组合框SelectedItem不在Itemssource中

WPF组合框SelectedItem不在Itemssource中,wpf,binding,combobox,selecteditem,itemssource,Wpf,Binding,Combobox,Selecteditem,Itemssource,如何使组合框的SelectedItem即使不在ItemsSource中也能显示出来 作为一个简单的例子 假设我有一个“Class”对象,上面有一个“Teacher”属性 public class Class: INotifyPropertyChanged { private Individual _teacher public Individual Teacher { get { return _teacher; } set {

如何使组合框的SelectedItem即使不在ItemsSource中也能显示出来

作为一个简单的例子

假设我有一个“Class”对象,上面有一个“Teacher”属性

public class Class: INotifyPropertyChanged
{
   private Individual _teacher
   public Individual Teacher
   {
      get { return _teacher; }
      set 
      {
         teacher = value;
         RaisePropertyChanged("Teacher");
      }
   }
   ...
}
在“维护课程”GUI上,有一个选择教师的组合框,我只希望活跃的个人出现在组合框中。我不希望用户能够在组合框中输入自由格式的文本。为了实现这一点,我将ItemsSource绑定到ViewModel中的一个集合,该集合仅包括活动的个人和绑定到“Class”对象的教师属性的SelectedItem

公共类维护类\u视图模型:INotifyPropertyChanged
{
私人可观察收集
=GetAllActivieIndividuals();
公众可观察的个人
{
获取{return}
}
公共类SelectedClass
{
得到;
设置
}
} 
我的组合框的xaml是

<ComboBox ItemsSource="{Binding ActiveIndividuals}" 
          SelectedItem="{Binding SelectedClass.Teacher}" />

现在,假设我打开一个类的“维护类”GUI,其中已保存的教师现在处于非活动状态。现在…我只希望活动的个人显示在组合框中,加上先前选择的教师(即使他们现在处于非活动状态,不在ItemsSource中)


目前,我找到的唯一方法是将不活动的个体添加到集合中,并引发集合的PropertyChanged事件。但是,我真的希望在不向集合中添加内容的情况下存档此结果。最好使用xaml、选择器和/或转换器的方法。

我就是这么做的使用,我希望它有助于:

ComboxAdapter.cs:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Markup;

    namespace Adaptors
    {
        [ContentProperty("ComboBox")]
        public class ComboBoxAdaptor : ContentControl
        {
            #region Protected Properties
            protected bool IsChangingSelection
            {get; set;}

            protected ICollectionView CollectionView
            {get; set;}
            #endregion

            #region Dependency Properties
            public static readonly DependencyProperty ComboBoxProperty = 
                DependencyProperty.Register("ComboBox", typeof(ComboBox), typeof(ComboBoxAdaptor),
                new FrameworkPropertyMetadata(new PropertyChangedCallback(ComboBox_Changed)));
            public ComboBox ComboBox
            {
                get { return (ComboBox)GetValue(ComboBoxProperty);}
                set { SetValue(ComboBoxProperty, value);}
            }

            public static readonly DependencyProperty NullItemProperty =
                DependencyProperty.Register("NullItem", typeof(object), typeof(ComboBoxAdaptor),
                new PropertyMetadata("(None)");
            public object NullItem
            {
                get {return GetValue(NullItemProperty);}
                set {SetValue(NullItemProperty, value);}
            }

            public static readonly DependencyProperty ItemsSourceProperty =
                DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(ComboBoxAdaptor),
                new FrameworkPropertyMetadata(new PropertyChangedCallback(ItemsSource_Changed)));
            public IEnumerable ItemsSource
            {
                get {return (IEnumerable)GetValue(ItemsSourceProperty);}
                set {SetValue(ItemsSourceProperty, value);}
            }

            public static readonly DependencyProperty SelectedItemProperty =
                DependencyProperty.Register("SelectedItem", typeof(object), typeof(ComboBoxAdaptor), 
                new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                new PropertyChangedCallback(SelectedItem_Changed)));
            public object SelectedItem
            {
                get {return GetValue(SelectedItemProperty);}
                set {SetValue(SelectedItemProperty, value);}
            }

            public static readonly DependencyProperty AllowNullProperty =
                DependencyProperty.Register("AllowNull", typeof(bool), typeof(ComboBoxAdaptor),
                new PropertyMetadata(true, AllowNull_Changed));
            public bool AllowNull
            {
                get {return (bool)GetValue(AllowNullProperty);}
                set {SetValue(AllowNullProperty, value);}
            }
            #endregion

            #region static PropertyChangedCallbacks
            static void ItemsSource_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                ComboBoxAdaptor adapter = (ComboBoxAdaptor)d;
                adapter.Adapt();
            }

            static void AllowNull_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                ComboBoxAdaptor adapter = (ComboBoxAdaptor)d;
                adapter.Adapt();
            }

            static void SelectedItem_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                ComboBoxAdaptor adapter = (ComboBoxAdaptor)d;
                if (adapter.ItemsSource != null)
                {
                    //If SelectedItem is changing from the Source (which we can tell by checking if the
                    //ComboBox.SelectedItem is already set to the new value), trigger Adapt() so that we
                    //throw out any items that are not in ItemsSource.
                    object adapterValue = (e.NewValue ?? adapter.NullItem);
                    object comboboxValue = (adapter.ComboBox.SelectedItem ?? adapter.NullItem);
                    if (!object.Equals(adapterValue, comboboxValue))
                    {
                        adapter.Adapt();
                        adapter.ComboBox.SelectedItem = e.NewValue;
                    }
                    //If the NewValue is not in the CollectionView (and therefore not in the ComboBox)
                    //trigger an Adapt so that it will be added.
                    else if (e.NewValue != null && !adapter.CollectionView.Contains(e.NewValue))
                    {
                        adapter.Adapt();
                    }
                }
            }
            #endregion

            #region Misc Callbacks
            void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (ComboBox.SelectedItem == NullItem)
                {
                    if (!IsChangingSelection)
                    {
                        IsChangingSelection = true;
                        try
                        {
                            int selectedIndex = ComboBox.SelectedIndex;
                            ComboBox.SelectedItem = null;
                            ComboBox.SelectedIndex = -1;
                            ComboBox.SelectedIndex = selectedIndex;
                        }
                        finally
                        {
                            IsChangingSelection = false;
                        }
                    }
                }
                object newVal = (ComboBox.SelectedItem == null? null: ComboBox.SelectedItem);
                if (!object.Equals(SelectedItem, newVal)
                {
                    SelectedItem = newVal;
                }
            }

            void CollectionView_CurrentChanged(object sender, EventArgs e)
            {
                if (AllowNull && (ComboBox != null) && (((ICollectionView)sender).CurrentItem == null) && (ComboBox.Items.Count > 0))
                {
                    ComboBox.SelectedIndex = 0;
                }
            }
            #endregion

            #region Methods
            protected void Adapt()
            {
                if (CollectionView != null)
                {
                    CollectionView.CurrentChanged -= CollectionView_CurrentChanged;
                    CollectionView = null;
                }
                if (ComboBox != null && ItemsSource != null)
                {
                    CompositeCollection comp = new CompositeCollection();
                    //If AllowNull == true, add a "NullItem" as the first item in the ComboBox.
                    if (AllowNull)
                    {
                        comp.Add(NullItem);
                    }
                    //Now Add the ItemsSource.
                    comp.Add(new CollectionContainer{Collection = ItemsSource});
                    //Lastly, If Selected item is not null and does not already exist in the ItemsSource,
                    //Add it as the last item in the ComboBox
                    if (SelectedItem != null)
                    {
                        List<object> items = ItemsSource.Cast<object>().ToList();
                        if (!items.Contains(SelectedItem))
                        {
                            comp.Add(SelectedItem);
                        }
                    }
                    CollectionView = CollectionViewSource.GetDefaultView(comp);
                    if (CollectionView != null)
                    {
                        CollectionView.CurrentChanged += CollectionView_CurrentChanged;
                    }
                    ComboBox.ItemsSource = comp
                }
            }
            #endregion
        }
    }
使用系统;
使用系统集合;
使用System.Collections.Generic;
使用系统组件模型;
使用System.Linq;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Data;
使用System.Windows.Markup;
名称空间适配器
{
[内容属性(“组合框”)]
公共类ComboboxAdapter:ContentControl
{
#区域保护属性
受保护的学校正在举行选举
{get;set;}
受保护的ICollectionView集合视图
{get;set;}
#端区
#区域依赖属性
公共静态只读DependencyProperty ComboBoxProperty=
DependencyProperty.Register(“ComboBox”)、typeof(ComboBox)、typeof(ComboboxAdapter),
新的FrameworkPropertyMetadata(新的PropertyChangedCallback(ComboBox_Changed));
公共组合框组合框
{
获取{return(ComboBox)GetValue(ComboBoxProperty);}
set{SetValue(ComboBoxProperty,value);}
}
公共静态只读DependencyProperty NullItemProperty=
DependencyProperty.Register(“NullItem”、typeof(object)、typeof(ComboboxAdapter),
新的不动产数据(“(无)”);
公共对象空项
{
获取{返回GetValue(NullItemProperty);}
set{SetValue(NullItemProperty,value);}
}
公共静态只读依赖项Property ItemsSourceProperty=
DependencyProperty.Register(“ItemsSource”、typeof(IEnumerable)、typeof(ComboboxAdapter),
新的FrameworkPropertyMetadata(新的PropertyChangedCallback(ItemsSource_Changed));
公共IEnumerable ItemsSource
{
get{return(IEnumerable)GetValue(ItemsSourceProperty);}
set{SetValue(ItemsSourceProperty,value);}
}
公共静态只读从属属性SelectedProperty=
DependencyProperty.Register(“SelectedItem”、typeof(对象)、typeof(ComboboxAdapter),
新建FrameworkPropertyMetadata(默认情况下为null,FrameworkPropertyMetadata选项.bindstwoway,
新属性更改回调(SelectedItem_Changed));
公共对象SelectedItem
{
获取{返回GetValue(SelectEditeProperty);}
设置{SetValue(SelectedItemProperty,value);}
}
公共静态只读DependencyProperty AllowNullProperty=
DependencyProperty.寄存器(“AllowFull”、typeof(bool)、typeof(ComboboxAdapter),
新属性元数据(正确,AllowNull_更改);
公共布尔AllowNull
{
获取{return(bool)GetValue(AllowNullProperty);}
set{SetValue(AllowNullProperty,value);}
}
#端区
#区域静态属性ChangedCallbacks
静态无效项资源已更改(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
ComboboxAdapter=(ComboboxAdapter)d;
adapter.Adapt();
}
静态void AllowNull_已更改(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
ComboboxAdapter=(ComboboxAdapter)d;
adapter.Adapt();
}
静态void SelectedItem\u已更改(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
ComboboxAdapter=(ComboboxAdapter)d;
if(adapter.ItemsSource!=null)
{
//如果SelectedItem正在从源更改(我们可以通过检查
//ComboBox.SelectedItem已设置为新值),触发器调整()以便
//扔掉所有不在ItemsSource中的项目。
对象adapterValue=(e.NewValue??adapter.NullItem);
对象comboboxValue=(adapter.ComboBox.SelectedItem??adapter.NullItem);
如果(!object.Equals)(
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Markup;

    namespace Adaptors
    {
        [ContentProperty("ComboBox")]
        public class ComboBoxAdaptor : ContentControl
        {
            #region Protected Properties
            protected bool IsChangingSelection
            {get; set;}

            protected ICollectionView CollectionView
            {get; set;}
            #endregion

            #region Dependency Properties
            public static readonly DependencyProperty ComboBoxProperty = 
                DependencyProperty.Register("ComboBox", typeof(ComboBox), typeof(ComboBoxAdaptor),
                new FrameworkPropertyMetadata(new PropertyChangedCallback(ComboBox_Changed)));
            public ComboBox ComboBox
            {
                get { return (ComboBox)GetValue(ComboBoxProperty);}
                set { SetValue(ComboBoxProperty, value);}
            }

            public static readonly DependencyProperty NullItemProperty =
                DependencyProperty.Register("NullItem", typeof(object), typeof(ComboBoxAdaptor),
                new PropertyMetadata("(None)");
            public object NullItem
            {
                get {return GetValue(NullItemProperty);}
                set {SetValue(NullItemProperty, value);}
            }

            public static readonly DependencyProperty ItemsSourceProperty =
                DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(ComboBoxAdaptor),
                new FrameworkPropertyMetadata(new PropertyChangedCallback(ItemsSource_Changed)));
            public IEnumerable ItemsSource
            {
                get {return (IEnumerable)GetValue(ItemsSourceProperty);}
                set {SetValue(ItemsSourceProperty, value);}
            }

            public static readonly DependencyProperty SelectedItemProperty =
                DependencyProperty.Register("SelectedItem", typeof(object), typeof(ComboBoxAdaptor), 
                new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                new PropertyChangedCallback(SelectedItem_Changed)));
            public object SelectedItem
            {
                get {return GetValue(SelectedItemProperty);}
                set {SetValue(SelectedItemProperty, value);}
            }

            public static readonly DependencyProperty AllowNullProperty =
                DependencyProperty.Register("AllowNull", typeof(bool), typeof(ComboBoxAdaptor),
                new PropertyMetadata(true, AllowNull_Changed));
            public bool AllowNull
            {
                get {return (bool)GetValue(AllowNullProperty);}
                set {SetValue(AllowNullProperty, value);}
            }
            #endregion

            #region static PropertyChangedCallbacks
            static void ItemsSource_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                ComboBoxAdaptor adapter = (ComboBoxAdaptor)d;
                adapter.Adapt();
            }

            static void AllowNull_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                ComboBoxAdaptor adapter = (ComboBoxAdaptor)d;
                adapter.Adapt();
            }

            static void SelectedItem_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                ComboBoxAdaptor adapter = (ComboBoxAdaptor)d;
                if (adapter.ItemsSource != null)
                {
                    //If SelectedItem is changing from the Source (which we can tell by checking if the
                    //ComboBox.SelectedItem is already set to the new value), trigger Adapt() so that we
                    //throw out any items that are not in ItemsSource.
                    object adapterValue = (e.NewValue ?? adapter.NullItem);
                    object comboboxValue = (adapter.ComboBox.SelectedItem ?? adapter.NullItem);
                    if (!object.Equals(adapterValue, comboboxValue))
                    {
                        adapter.Adapt();
                        adapter.ComboBox.SelectedItem = e.NewValue;
                    }
                    //If the NewValue is not in the CollectionView (and therefore not in the ComboBox)
                    //trigger an Adapt so that it will be added.
                    else if (e.NewValue != null && !adapter.CollectionView.Contains(e.NewValue))
                    {
                        adapter.Adapt();
                    }
                }
            }
            #endregion

            #region Misc Callbacks
            void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (ComboBox.SelectedItem == NullItem)
                {
                    if (!IsChangingSelection)
                    {
                        IsChangingSelection = true;
                        try
                        {
                            int selectedIndex = ComboBox.SelectedIndex;
                            ComboBox.SelectedItem = null;
                            ComboBox.SelectedIndex = -1;
                            ComboBox.SelectedIndex = selectedIndex;
                        }
                        finally
                        {
                            IsChangingSelection = false;
                        }
                    }
                }
                object newVal = (ComboBox.SelectedItem == null? null: ComboBox.SelectedItem);
                if (!object.Equals(SelectedItem, newVal)
                {
                    SelectedItem = newVal;
                }
            }

            void CollectionView_CurrentChanged(object sender, EventArgs e)
            {
                if (AllowNull && (ComboBox != null) && (((ICollectionView)sender).CurrentItem == null) && (ComboBox.Items.Count > 0))
                {
                    ComboBox.SelectedIndex = 0;
                }
            }
            #endregion

            #region Methods
            protected void Adapt()
            {
                if (CollectionView != null)
                {
                    CollectionView.CurrentChanged -= CollectionView_CurrentChanged;
                    CollectionView = null;
                }
                if (ComboBox != null && ItemsSource != null)
                {
                    CompositeCollection comp = new CompositeCollection();
                    //If AllowNull == true, add a "NullItem" as the first item in the ComboBox.
                    if (AllowNull)
                    {
                        comp.Add(NullItem);
                    }
                    //Now Add the ItemsSource.
                    comp.Add(new CollectionContainer{Collection = ItemsSource});
                    //Lastly, If Selected item is not null and does not already exist in the ItemsSource,
                    //Add it as the last item in the ComboBox
                    if (SelectedItem != null)
                    {
                        List<object> items = ItemsSource.Cast<object>().ToList();
                        if (!items.Contains(SelectedItem))
                        {
                            comp.Add(SelectedItem);
                        }
                    }
                    CollectionView = CollectionViewSource.GetDefaultView(comp);
                    if (CollectionView != null)
                    {
                        CollectionView.CurrentChanged += CollectionView_CurrentChanged;
                    }
                    ComboBox.ItemsSource = comp
                }
            }
            #endregion
        }
    }
<adaptor:ComboBoxAdaptor 
         NullItem="Please Select an Item.."
         ItemsSource="{Binding MyItemsSource}"
         SelectedItem="{Binding MySelectedItem}">
      <ComboBox Width="100" />
</adaptor:ComboBoxAdaptor>