wpf 使用 MVVM 重置组合框选定的项目

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17854611/
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 09:16:58  来源:igfitidea点击:

Reset combobox selected item on set using MVVM

c#wpfmvvmcomboboxselecteditem

提问by fhnaseer

I am using a ComboBox in my WPF application and following MVVM. There is a list of strings which I want to show in my ComboBox.

我在 WPF 应用程序中使用 ComboBox 并遵循 MVVM。我想在 ComboBox 中显示一个字符串列表。

XAML:

XAML:

<ComboBox ItemsSource="{Binding ItemsCollection}" SelectedItem="{Binding SelectedItem}" />

View Model:

查看型号:

public Collection<string> ItemsCollection; // Suppose this has 10 values.
private string _selectedItem;
public string SelectedItem
{
    get { return _selectedItem; }
    set
    {
        _selectedItem = value;
        Trigger Notify of property changed.
    }
}

Now this code is working absolutely fine. I am able to select from view and I can get changes in ViewModel and if I change SelectedItem from my ViewModel I can see it in my view.

现在这段代码工作得很好。我可以从视图中进行选择,并且可以在 ViewModel 中进行更改,如果我从 ViewModel 中更改 SelectedItem,则可以在我的视图中看到它。

Now here is what I am trying to achieve. When I change selected item from my view I need to put a check that value is good/bad (or anything) set selected item else do not set it. So my view model changes like to this.

现在这就是我想要实现的目标。当我从我的视图中更改选定的项目时,我需要检查值是好/坏(或任何)设置选定的项目,否则不要设置它。所以我的视图模型变成了这样。

public string SelectedItem
{
    get { return _selectedItem; }
    set
    {
        if (SomeCondition(value))
            _selectedItem = value;           // Update selected item.
        else
            _selectedItem = _selectedItem;   // Do not update selected item.
        Trigger Notify of property changed.
    }
}

Now when I execute this code and SomeCondition(value) returns false, SelectedItem returns old string value, but in my view selected item in ComboBox is the the value which I selected. So lets assume I have collection of 10 strings showing in my ComboBox. All values are good except second and fourth element (SomeCondition returns false for 2nd and 4th value). What I want that if I select 2nd or 4th element selectedItem do not change. But my code is not doing this properly. If I select 2nd element then view still displays 2nd element as selected. I know there is something wrong in my code. But what is it?

现在,当我执行此代码并且 SomeCondition(value) 返回 false 时,SelectedItem 返回旧字符串值,但在我看来,ComboBox 中的选定项是我选择的值。所以让我们假设我的 ComboBox 中显示了 10 个字符串的集合。除了第二个和第四个元素外,所有值都很好(SomeCondition 为第二个和第四个值返回 false)。如果我选择第 2 个或第 4 个元素 selectedItem,我想要什么不要改变。但是我的代码没有正确执行此操作。如果我选择第二个元素,则视图仍将第二个元素显示为选定的。我知道我的代码有问题。但它是什么?

回答by Bill Zhang

This is a very interesting question. First I agree with other guys that this is a not recommended approach to handle invalid selection. As @blindmeis suggests, IDataErrorInfois one of good way to solve it.

这是一个非常有趣的问题。首先,我同意其他人的看法,这是处理无效选择的不推荐方法。正如@blindmeis 所暗示的那样,IDataErrorInfo是解决它的好方法之一。

Back to the question itself. A solution satisfying what @Faisal Hafeez wants is:

回到问题本身。满足@Faisal Hafeez 想要的解决方案是:

public string SelectedItem
{
    get { return _selectedItem; }
    set
    {
        var oldItem=_selectedItem;
        _selectedItem=value;
        OnPropertyChanged("SelectedItem")

        if (!SomeCondition(value)) //If does not satisfy condition, set item back to old item
            Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => SelectedItem = oldItem),
                                                 DispatcherPriority.ApplicationIdle);
    }
}

Dispatcheris an elegant way to handle some UI synchronization during another UI sync. For example in this case, you want to reset selection during a selection binding.

Dispatcher是在另一个 UI 同步期间处理某些 UI 同步的优雅方式。例如,在这种情况下,您希望在选择绑定期间重置选择。

A question here is why we have to update selection anyway at first. That's because SelectedItemand SelectedValueare separately assigned and what display on ComboBoxdoes not depend on SelectedItem(maybe SelectedValue, I am not sure here). And another interesting point is if SelectedValue changes, SelectedItemmust change but SelectedItemdoes not update SelectedValuewhen it changes. Therefore, you can choose to bind to SelectedValueso that you do not have to assign first.

这里的一个问题是为什么我们首先必须更新选择。那是因为SelectedItemSelectedValue是单独分配的,ComboBox并且不依赖于显示的内容SelectedItem(也许SelectedValue,我在这里不确定)。另一个有趣的一点是,如果 SelectedValue 发生变化,则SelectedItem必须更改但SelectedItem不会SelectedValue在更改时更新。因此,您可以选择绑定到,SelectedValue这样您就不必先分配。

回答by Haris Hasan

Try changing the XAML to this

尝试将 XAML 更改为此

<ComboBox ItemsSource="{Binding ItemsCollection}" SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

回答by LukeVidalis

I know this is a bit late but as of WPF 4.5 you can use the Delay command like so:

我知道这有点晚了,但从 WPF 4.5 开始,您可以像这样使用 Delay 命令:

    <ComboBox ItemsSource="{Binding ItemsCollection}" SelectedItem="{Binding SelectedItem, Mode=TwoWay, Delay=1, UpdateSourceTrigger=PropertyChanged}" />

This saved me after hours of looking up stuff the other day. For other methods which may or may not work you can read thispost and its comments.

这让我在前几天查了几个小时的东西后救了我。对于其他可能有效也可能无效的方法,您可以阅读这篇文章及其评论。

回答by MigRome

<ComboBox ItemsSource="{Binding ItemsCollection}" SelectedIndex="{Binding currSelection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged} " />

And in your VM

在你的虚拟机中

{
    set{ 
        currSelection = -1;
    }
}

回答by TravisWhidden

If you are looking for a MVVM / XAML re-usable solution, I put this together for another thread. This uses a WPF Behavior and is very simple to manage. No external libs. Copy in solution.

如果您正在寻找 MVVM/XAML 可重用的解决方案,我将其放在另一个线程中。这使用 WPF 行为并且非常易于管理。没有外部库。在解决方案中复制。

ComboBox Selected Item Clear Behavior

ComboBox 选定项清除行为