13

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

XAML:

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

查看型号:

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.
    }
}

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

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

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.
    }
}

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

4

5 回答 5

24

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

回到问题本身。满足@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);
    }
}

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

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

于 2013-07-25T15:00:46.407 回答
11

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

    <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 this post and its comments.

于 2019-11-19T08:45:53.403 回答
3

尝试将 XAML 更改为此

<ComboBox ItemsSource="{Binding ItemsCollection}" SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
于 2013-07-25T09:54:47.253 回答
0

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

ComboBox 选定项清除行为

于 2019-03-20T00:15:55.047 回答
0
<ComboBox ItemsSource="{Binding ItemsCollection}" SelectedIndex="{Binding currSelection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged} " />

在你的虚拟机中

{
    set{ 
        currSelection = -1;
    }
}
于 2018-08-31T20:56:44.750 回答