WPF:带有重置项的组合框

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16009629/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 08:36:24  来源:igfitidea点击:

WPF: ComboBox with reset item

c#.netwpfxamlcombobox

提问by Staeff

I want to make a ComboBox in WPF that has one nullitem on the top, when this gets selected, the SelectedItem should be set to null (reset to default state). I've searched like forever, but didn't find a solution that was satisfying.

我想在 WPF 中创建一个null顶部有一个项目的 ComboBox ,当它被选中时,SelectedItem 应设置为 null(重置为默认状态)。我一直在寻找,但没有找到令人满意的解决方案。

If possible I would want it to do it only with XAML code or an attached behaviour, because I don't really like changing stuff in the ViewModel for the View, or overriding standard controls.

如果可能,我希望它只使用 XAML 代码或附加的行为来完成它,因为我真的不喜欢更改 ViewModel 中的内容或覆盖标准控件。

Here is what I've come up with so far (shortened code):

到目前为止,这是我想出的(缩短的代码):

[...]
<Popup x:Name="PART_Popup" [...]>
    <Border x:Name="PopupBorder" [...]>
        <ScrollViewer x:Name="DropDownScrollViewer" [...]>
            <StackPanel [...]>
                <ComboBoxItem>(None)</ComboBoxItem>
                <ItemsPresenter x:Name="ItemsPresenter"/>
            </StackPanel>
        </ScrollViewer>
    </Border>
</Popup>
[...]

OpenCombo

开放组合

I think the best way would be to somehow add an event trigger that sets the SelectedIndexto -1when the item gets selected, but here is where I've got stuck.

我认为最好的办法就是以某种方式添加一个事件触发器,套SelectedIndex-1当项目被选中,但这里是我卡住了。

Any ideas how to do this? Or an better way, like an attached behaviour?

任何想法如何做到这一点?或者更好的方式,比如附加行为?

回答by Andrei Zubov

Think about implementing a Null Object Patternfor the "None" combobox item and add this item to your items list. Then implement custom logic for saving null object in that class, or just check if selected item is of NullItem type.

考虑为“无”组合框项目实现空对象模式并将此项目添加到您的项目列表中。然后实现自定义逻辑以在该类中保存空对象,或者只检查所选项目是否为 NullItem 类型。

回答by dtm

I used the following solution for a similar problem. It makes use of the Converter property of the binding to go back and forth between the internal representation (that null is a reasonable value) and what I want to appear in the ComboBox. I like that there's no need to add an explicit list in a model or viewmodel, but I don't like the fragile connection between the string literal in the converter and that in the ComboBox.

我对类似的问题使用了以下解决方案。它利用绑定的 Converter 属性在内部表示(null 是一个合理的值)和我想要出现在 ComboBox 中的内容之间来回切换。我喜欢不需要在模型或视图模型中添加显式列表,但我不喜欢转换器中的字符串文字与 ComboBox 中的字符串文字之间的脆弱连接。

<ComboBox SelectedValue="{Binding MyProperty, Converter={x:Static Converters:MyPropertySelectionConverter.Instance}}" >
    <ComboBox.ItemsSource>
        <CompositeCollection>
            <sys:String>(none)</sys:String>
            <CollectionContainer Collection="{Binding Source={x:Static Somewhere}, Path=ListOfPossibleValuesForMyProperty}" />
        </CompositeCollection>
    </ComboBox.ItemsSource>
</ComboBox>

and then the converter looks like:

然后转换器看起来像:

public class MyPropertySelectionConverter : IValueConverter
{
    public static MyPropertySelectionConverter Instance
    {
        get { return s_Instance; }
    }

    public const String NoneString = "(none)";

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Object retval = value as MyPropertyType;
        if (retval == null)
        {
            retval = NoneString;
        }
        return retval;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Object retval = null;
        if (value is MyPropertyType)
        {
            retval = value;
        }
        else if (String.Equals(NoneString, value as String, StringComparison.OrdinalIgnoreCase))
        {
            retval = null;
        }
        else
        {
            retval = DependencyProperty.UnsetValue;
        }
        return retval;
    }


    private static MyPropertySelectionConverter s_Instance = new MyPropertySelectionConverter();
}

回答by LPL

It is possible to reset the selection if you select an item.

如果您选择了一个项目,则可以重置选择。

<ComboBox x:Name="cb">
    <ComboBox.Items>
        <ComboBoxItem Content="(None)">
            <ComboBoxItem.Triggers>
                <EventTrigger RoutedEvent="Selector.Selected">
                    <BeginStoryboard>
                        <Storyboard Storyboard.TargetName="cb" Storyboard.TargetProperty="SelectedItem">
                            <ObjectAnimationUsingKeyFrames Duration="0:0:0">
                                <DiscreteObjectKeyFrame Value="{x:Null}" />
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>                               
                </EventTrigger>
            </ComboBoxItem.Triggers>
        </ComboBoxItem>
        <ComboBoxItem>First Item</ComboBoxItem>
        <ComboBoxItem>Second Item</ComboBoxItem>
    </ComboBox.Items>
</ComboBox>

Unfortunately this will not work with ItemsSourceand a CompositeCollectionto add this reset item to an arbitrary list. The reason is WPF can't resolve the Storyboard.TargetNamein this scope. But maybe this helps you go on with retemplating the ComboBox.

不幸的是这不会与工作ItemsSourceCompositeCollection这个重置项目添加到任意目录。原因是 WPF 无法解决Storyboard.TargetName此范围内的问题。但也许这可以帮助您继续重新设计ComboBox.

回答by Julio Nobre

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

虽然我同意WPF ComboBoxnull 项问题有很多解决方案,但Andrei Zubov 对 Null Object Pattern 的引用启发了我尝试一种不那么矫枉过正的替代方案,包括在注入之前用值(也包装)包装每个源项目允许整个包装的集合到ComboBox.ItemsSource属性。所选项目将可用于SelectedWrappedItem属性。

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
{

    /// <summary>
    /// Wrapper that adds supports to null values upon ComboBox.ItemsSource
    /// </summary>
    /// <typeparam name="T">Source combobox items collection datatype</typeparam>
    public class ComboBoxNullableItemWrapper<T>
    {
        string _nullValueText;

        private T _value;

        public T Value
        {
            get { return _value; }
            set { _value = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Value">Source object</param>
        /// <param name="NullValueText">Text to be presented whenever Value argument object is NULL</param>
        public ComboBoxNullableItemWrapper(T Value, string NullValueText = "(none)")
        {
            this._value = Value;
            this._nullValueText = NullValueText;
        }

        /// <summary>
        /// Text that will be shown on combobox items
        /// </summary>
        /// <returns></returns>
        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<Person> _SelectedWrappedItem { get; set; }

        public ComboBoxNullableItemWrapper<Person> SelectedWrappedItem
        {
            get { return _SelectedWrappedItem; }
            set
            {
                _SelectedWrappedItem = value;
                OnPropertyChanged("SelectedWrappedItem");
            }
        }

        // ListOfPersons - Collection to be injected into ComboBox.ItemsSource property
        public ObservableCollection<ComboBoxNullableItemWrapper<Person>> 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<Person> RegularList = new List<Person>();
            RegularList.Add(person1);
            RegularList.Add(person2);

            // Convert regular collection into a wrapped collection
            ListOfPersons = new ObservableCollection<ComboBoxNullableItemWrapper<Person>>();
            ListOfPersons.Add(new ComboBoxNullableItemWrapper<Person>(null));
            RegularList.ForEach(x => ListOfPersons.Add(new ComboBoxNullableItemWrapper<Person>(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)

而且,最终你的视图(好吧,它是一个窗口)

<Window x:Class="ComboBoxWrapperSample.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"        
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:ComboBoxWrapperSample"
            xmlns:vm="clr-namespace:ComboBoxWrapperSample"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:ignore="http://www.ignore.com"
            mc:Ignorable="d"
            d:DataContext="{d:DesignInstance {x:Type vm:SampleViewModel}, IsDesignTimeCreatable=False}"
            Title="MainWindow" Height="200" Width="300">
    <StackPanel Orientation="Vertical" Margin="10">
        <TextBlock Margin="0,10,0,0">Favorite teacher</TextBlock>
        <ComboBox ItemsSource="{Binding ListOfPersons}"
                SelectedItem="{Binding SelectedWrappedItem, Mode=TwoWay}">
        </ComboBox>
        <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
            <TextBlock>Selected wrapped value:</TextBlock>
            <TextBlock Text="{Binding SelectedWrappedItem }" Margin="5,0,0,0" FontWeight="Bold"/>
        </StackPanel>
    </StackPanel>
</Window>

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

谈到这一点,我是否提到您可以通过SelectedWrappedItem.Value属性检索未包装的选定项目?

Here you can get a working sample

在这里你可以得到一个工作样本

Hope it helps someone else

希望它能帮助别人

回答by softworkz

Here's the ultimate super-simple solution to this problem:

这是这个问题的终极超级简单解决方案:

Instead of having an item with a value of null in your ItemsSource, use DbNull.Value as item or as the item's value property.

不要在 ItemsSource 中使用值为 null 的项目,而是使用 DbNull.Value 作为项目或项目的 value 属性。

That's all. You're done. No value converters, no code-behind, no xaml triggers, no wrappers, no control descendants...

就这样。你完成了。没有值转换器,没有代码隐藏,没有 xaml 触发器,没有包装器,没有控制后代......

It simply works!

它只是有效!

Here's a short example for binding enum values including a "null item":

这是绑定枚举值的简短示例,包括“空项目”:

Create your ItemsSource like this:

像这样创建您的 ItemsSource:

   var enumValues = new ArrayList(Enum.GetValues(typeof(MyEnum)));

   enumValues.Insert(0, DBNull.Value);

   return enumValues;

Bind this to the ItemsSource of the ComboBox.

将此绑定到 ComboBox 的 ItemsSource。

Bind the SelectedValue of your ComboBox to any Property having a Type of MyEnum? (i.e. Nullable<MyEnum>).

将 ComboBox 的 SelectedValue 绑定到任何具有 MyEnum 类型的属性?(即 Nullable<MyEnum>)。

Done!

完毕!

Background: This approach works because DbNull.Value is not the same like a C# null value, while on the other hand the framework includes a number of coercion methods to convert between those two. Eventually, this is similar to the mentioned "Null object pattern", but without the need for creating an individual null object and without the need for any value converters.

背景:此方法有效,因为 DbNull.Value 与 C# 空值不同,而另一方面,框架包含许多强制方法来在这两者之间进行转换。最终,这类似于提到的“空对象模式”,但不需要创建单独的空对象,也不需要任何值转换器。

回答by TravisWhidden

A little more elaborate than some answers here, but didn't want to have any code behind or ViewModel changes in mine. I wrote this as a WPF behavior. When attached to the XAML, it will inject a button in the visual. It will set the Default value of -1 (or you can adjust to be something else default). This is a re-usable control that is easy to add on your XAML throughout your project. Hope this helps. Open to feedback if you spot an error.

比这里的一些答案更详细一点,但不想在我的背后有任何代码或 ViewModel 更改。我将其写为 WPF 行为。当附加到 XAML 时,它将在视觉对象中注入一个按钮。它会将默认值设置为 -1(或者您可以调整为其他默认值)。这是一个可重用的控件,可以轻松地在整个项目中添加到 XAML 中。希望这可以帮助。如果您发现错误,欢迎反馈。

  1. There are no external references, you can use this with your code and no other DLLs. (well, it does use System.Windows.Interactivity but most will have this in WPF apps)
  2. Its re-usable throughout your application
  3. Style will conform to your themes.
  4. You can Hyman this up all you want
  5. I know this is an almost 6 year old thread (as of my writing in 2019), but if you like it -- make it the answer since there isn't one!
  1. 没有外部引用,您可以将其与您的代码一起使用,而无需其他 DLL。(好吧,它确实使用 System.Windows.Interactivity 但大多数会在 WPF 应用程序中使用)
  2. 它可以在整个应用程序中重复使用
  3. 风格将符合您的主题。
  4. 你可以随心所欲
  5. 我知道这是一个已有近 6 年历史的线程(截至我在 2019 年撰写的文章),但如果您喜欢它 - 让它成为答案,因为没有一个!

Resulting Visual:

结果视觉:

Item Selected:

选择的项目:

ComboBox Clear Example

组合框清除示例

Behavior Code:

行为准则:

public class ComboBoxClearBehavior : Behavior<ComboBox>
{
    private Button _addedButton;
    private ContentPresenter _presenter;
    private Thickness _originalPresenterMargins;

    protected override void OnAttached()
    {
        // Attach to the Loaded event. The visual tree at this point is not available until its loaded.
        AssociatedObject.Loaded += AssociatedObject_Loaded;

        // If the user or code changes the selection, re-evaluate if we should show the clear button
        AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;

        base.OnAttached();
    }

    protected override void OnDetaching()
    {
        // Its likely that this is already de-referenced, but just in case the visual was never loaded, we will remove the handler anyways.
        AssociatedObject.Loaded -= AssociatedObject_Loaded;
        base.OnDetaching();
    }

    private void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        EvaluateDisplay();
    }

    /// <summary>
    /// Checks to see if the UI should show a Clear button or not based on what is or isn't selected.
    /// </summary>
    private void EvaluateDisplay()
    {
        if (_addedButton == null) return;
        _addedButton.Visibility = AssociatedObject.SelectedIndex == -1 ? Visibility.Collapsed : Visibility.Visible;

        // To prevent the text or content from being overlapped by the button, adjust the margins if we have reference to the presenter.
        if (_presenter != null)
        {
            _presenter.Margin = new Thickness(
                _originalPresenterMargins.Left, 
                _originalPresenterMargins.Top, 
                _addedButton.Visibility == Visibility.Visible ? ClearButtonSize + 6 : _originalPresenterMargins.Right, 
                _originalPresenterMargins.Bottom);
        }
    }

    private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        // After we have loaded, we will have access to the Children objects. We don't want this running again.
        AssociatedObject.Loaded -= AssociatedObject_Loaded;

        // The ComboBox primary Grid is named  MainGrid. We need this to inject the button control. If missing, you may be using a custom control.
        if (!(AssociatedObject.FindChild("MainGrid") is Grid grid)) return;

        // Find the content presenter. We need this to adjust the margins if the Clear icon is present.
        _presenter = grid.FindChildren<ContentPresenter>().FirstOrDefault();
        if (_presenter != null) _originalPresenterMargins = _presenter.Margin;

        // Create the new button to put in the view
        _addedButton = new Button
        {
            Height = ClearButtonSize, 
            Width = ClearButtonSize,
            HorizontalAlignment = HorizontalAlignment.Right
        };


        // Find the resource for the button - In this case, our NoChromeButton Style has no button edges or chrome
        if (Application.Current.TryFindResource("NoChromeButton") is Style style)
        {
            _addedButton.Style = style;
        }

        // Find the resource you want to put in the button content
        if (Application.Current.TryFindResource("RemoveIcon") is FrameworkElement content)
        {
            _addedButton.Content = content;
        }

        // Hook into the Click Event to handle clearing
        _addedButton.Click += ClearSelectionButtonClick;

        // Evaluate if we should display. If there is nothing selected, don't show.
        EvaluateDisplay();

        // Add the button to the grid - First Column as it will be right justified.
        grid.Children.Add(_addedButton);
    }

    private void ClearSelectionButtonClick(object sender, RoutedEventArgs e)
    {
        // Sets the selected index to -1 which will set the selected item to null.
        AssociatedObject.SelectedIndex = -1;
    }

    /// <summary>
    /// The Button Width and Height. This can be changed in the Xaml if a different size visual is desired.
    /// </summary>
    public int ClearButtonSize { get; set; } = 15;
}

Usage:

用法:

<ComboBox 
 ItemsSource="{Binding SomeItemsSource, Mode=OneWay}"
 SelectedValue="{Binding SomeId, Mode=TwoWay}"
 SelectedValuePath="SomeId">
  <i:Interaction.Behaviors>
    <behaviors:ComboBoxClearBehavior />
  </i:Interaction.Behaviors>
</ComboBox>

You will need two things for this Behavior -- you may already have them, but here they are:

对于此行为,您将需要两件事——您可能已经拥有它们,但它们是:

1.) The Button Template - The code is looking for a style. In my case, it's called NoChromeButton- If you are looking for a turnkey solution, you can add mine to your resources file:

1.) 按钮模板 - 代码正在寻找一种样式。就我而言,它称为 NoChromeButton-如果您正在寻找交钥匙解决方案,您可以将我的解决方案添加到您的资源文件中:

<Style x:Key="NoChromeButton"
       TargetType="{x:Type Button}">
    <Setter Property="Background"
            Value="Transparent" />
    <Setter Property="BorderThickness"
            Value="1" />
    <Setter Property="Foreground"
            Value="{DynamicResource WindowText}" />
    <Setter Property="HorizontalContentAlignment"
            Value="Center" />
    <Setter Property="VerticalContentAlignment"
            Value="Center" />
    <Setter Property="Cursor"
            Value="Hand"/>
    <Setter Property="Padding"
            Value="1" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Grid x:Name="Chrome"
                      Background="{TemplateBinding Background}"
                      SnapsToDevicePixels="true">
                    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                      Margin="{TemplateBinding Padding}"
                                      RecognizesAccessKey="True"
                                      SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled"
                             Value="false">
                        <Setter Property="Foreground"
                                Value="#ADADAD" />
                        <Setter Property="Opacity"
                                TargetName="Chrome"
                                Value="0.5" />
                    </Trigger>
                    <Trigger
                        Property="IsMouseOver"
                        Value="True">
                        <Setter
                            TargetName="Chrome"
                            Property="Background"
                            Value="{DynamicResource ButtonBackgroundHover}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Also you will need your icon for the clear. If you have one, just update the code to use that resource (named "RemoveIcon"). Otherwize.. here is mine:

此外,您还需要您的图标来清晰显示。如果您有,只需更新代码即可使用该资源(名为“RemoveIcon”)。否则..这是我的:

<Viewbox x:Key="RemoveIcon"
         x:Shared="False"
         Stretch="Uniform">
    <Canvas Width="58"
            Height="58">
        <Path Fill="{Binding Foreground, RelativeSource={RelativeSource AncestorType=Control, Mode=FindAncestor}}">
            <Path.Data>
                <PathGeometry Figures="M 29 0 C 13 0 0 13 0 29 0 45 13 58 29 58 45 58 58 45 58 29 58 13 45 0 29 0 Z M 43.4 40.6 40.6 43.4 29 31.8 17.4 43.4 14.6 40.6 26.2 29 14.6 17.4 17.4 14.6 29 26.2 40.6 14.6 43.4 17.4 31.8 29 Z"
                              FillRule="NonZero" />
            </Path.Data>
        </Path>
    </Canvas>
</Viewbox>

回答by Ramesh

Remove the following line and add a CheckBox, then you can perform your custom operation.

删除以下行并添加一个 CheckBox,然后您就可以执行您的自定义操作。

    <ComboBoxItem>(None)</ComboBoxItem>

回答by Staeff

Still not 100% happy with this solution, but the best thing I found so far, you only need to override the ComboBox Style and apply an AttachedBehaviour.

对这个解决方案仍然不是 100% 满意,但到目前为止我发现的最好的事情是,您只需要覆盖 ComboBox 样式并应用AttachedBehaviour.

<ComboBox ItemsSource="{Binding Names}"
          ext:ComboBoxHelper.IsNullable="True" />

Source: http://xamlblog.com/PostPage.aspx?postId=16#/Posts/16

来源:http: //xamlblog.com/PostPage.aspx?postId=16#/Posts/16

Edit:Link to the Internet Archive since the link is broken: https://web.archive.org/web/20160420174905/http://xamlblog.com/PostPage.aspx?postId=16

编辑:由于链接断开,链接到 Internet Archive:https: //web.archive.org/web/20160420174905/http: //xamlblog.com/PostPage.aspx?postId=16

回答by Ramesh

Please use the following code.

请使用以下代码。

    <ComboBoxItem IsSelected="{Binding ClearSelectedItems}">(None)</ComboBoxItem>

In the viewmodel, catch the "ClearSelectedItems" change notification and clear the SelectedItems of ItemsControl.

在视图模型中,捕获“ClearSelectedItems”更改通知并清除 ItemsControl 的 SelectedItems。