WPF: ComboBox with reset item

后端 未结 9 1919
长发绾君心
长发绾君心 2020-12-15 23:33

I want to make a ComboBox in WPF that has one null item on the top, when this gets selected, the SelectedItem should be set to null (reset to default state). I\

9条回答
  •  时光取名叫无心
    2020-12-15 23:43

    While I agree there are plenty solutions to WPF ComboBox's null item issue, Andrei Zubov's reference to Null Object Pattern inspired me to try a less overkilling alternative, which consists on wrapping every source item allow with a null value (also wrapped) before injecting the whole wrapped collection into ComboBox.ItemsSource property. Selected item will be available into SelectedWrappedItem property.

    So, first you define your generic Wrapper...

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ComboBoxWrapperSample
    {
    
        /// 
        /// Wrapper that adds supports to null values upon ComboBox.ItemsSource
        /// 
        /// Source combobox items collection datatype
        public class ComboBoxNullableItemWrapper
        {
            string _nullValueText;
    
            private T _value;
    
            public T Value
            {
                get { return _value; }
                set { _value = value; }
            }
    
            /// 
            /// 
            /// 
            /// Source object
            /// Text to be presented whenever Value argument object is NULL
            public ComboBoxNullableItemWrapper(T Value, string NullValueText = "(none)")
            {
                this._value = Value;
                this._nullValueText = NullValueText;
            }
    
            /// 
            /// Text that will be shown on combobox items
            /// 
            /// 
            public override string ToString()
            {
                string result;
                if (this._value == null)
                    result = _nullValueText;
                else
                    result = _value.ToString();
                return result;
            }
    
        }
    }
    

    Define your item model...

    using System.ComponentModel;
    
    namespace ComboBoxWrapperSample
    {
        public class Person : INotifyPropertyChanged
        {
            // Declare the event
            public event PropertyChangedEventHandler PropertyChanged;
    
            public Person()
            {
            }
    
            // Name property
            private string _name;
    
            public string Name
            {
                get { return _name; }
                set
                {
                    _name = value;
                    OnPropertyChanged("Name");
                }
            }
    
            // Age property
            private int _age;
    
            public int Age
            {
                get { return _age; }
                set
                {
                    _age = value;
                    OnPropertyChanged("Age");
                }
            }
    
            protected void OnPropertyChanged(string name)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(name));
                }
            }
    
            // Don't forget this override, since it's what defines ao each combo item is shown
            public override string ToString()
            {
                return string.Format("{0} (age {1})", Name, Age);
            }
        }
    }
    

    Define your ViewModel...

    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    
    namespace ComboBoxWrapperSample
    {
        public partial class SampleViewModel : INotifyPropertyChanged
        {
    
            // SelectedWrappedItem- This property stores selected wrapped item
            public ComboBoxNullableItemWrapper _SelectedWrappedItem { get; set; }
    
            public ComboBoxNullableItemWrapper SelectedWrappedItem
            {
                get { return _SelectedWrappedItem; }
                set
                {
                    _SelectedWrappedItem = value;
                    OnPropertyChanged("SelectedWrappedItem");
                }
            }
    
            // ListOfPersons - Collection to be injected into ComboBox.ItemsSource property
            public ObservableCollection> ListOfPersons { get; set; }
    
            public SampleViewModel()
            {
    
                // Setup a regular items collection
                var person1 = new Person() { Name = "Foo", Age = 31 };
                var person2 = new Person() { Name = "Bar", Age = 42 };
    
                List RegularList = new List();
                RegularList.Add(person1);
                RegularList.Add(person2);
    
                // Convert regular collection into a wrapped collection
                ListOfPersons = new ObservableCollection>();
                ListOfPersons.Add(new ComboBoxNullableItemWrapper(null));
                RegularList.ForEach(x => ListOfPersons.Add(new ComboBoxNullableItemWrapper(x)));
    
                // Set UserSelectedItem so it targes null item
                this.SelectedWrappedItem = ListOfPersons.Single(x => x.Value ==null);
    
            }
    
            // INotifyPropertyChanged related stuff
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void OnPropertyChanged(string name)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(name));
                }
            }
        }
    }
    

    And, finnaly your View (ok, it's a Window)

    
        
            Favorite teacher
            
            
            
                Selected wrapped value:
                
            
        
    
    

    Reaching this point, did I mention that you could retrieve unwrapped selected item thru SelectedWrappedItem.Value property ?

    Here you can get a working sample

    Hope it helps someone else

提交回复
热议问题