我在我的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不改变。但是我的代码没有正确地执行此操作。如果我选择第二个元素,则视图仍然显示第二个元素为选中。我知道我的代码有问题。但它是什么?
答案 0 :(得分:18)
这是一个非常有趣的问题。首先,我同意其他人的意见,这是一种不推荐的处理无效选择的方法。正如@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同步的优雅方式。例如,在这种情况下,您希望在选择绑定期间重置选择。
这里的一个问题是为什么我们必须首先更新选择。这是因为SelectedItem
和SelectedValue
是单独分配的,ComboBox
上显示的内容不依赖SelectedItem
(也许SelectedValue
,我不确定)。另一个有趣的观点是,如果SelectedValue发生更改,SelectedItem
必须更改,但SelectedItem
在更改时不会更新SelectedValue
。因此,您可以选择绑定到SelectedValue
,这样就不必先进行分配。
答案 1 :(得分:3)
尝试将XAML更改为此
<ComboBox ItemsSource="{Binding ItemsCollection}" SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
答案 2 :(得分:0)
<ComboBox ItemsSource="{Binding ItemsCollection}" SelectedIndex="{Binding currSelection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged} " />
在您的VM中
{
set{
currSelection = -1;
}
}
答案 3 :(得分:0)
如果您正在寻找MVVM / XAML可重用的解决方案,我将其组合在一起用于另一个线程。这使用WPF行为,并且非常易于管理。没有外部库。复制解决方案。
答案 4 :(得分:0)
我知道这有点晚了,但是从WPF 4.5开始,您可以像下面这样使用Delay命令:
<ComboBox ItemsSource="{Binding ItemsCollection}" SelectedItem="{Binding SelectedItem, Mode=TwoWay, Delay=1, UpdateSourceTrigger=PropertyChanged}" />
前几天经过数小时的查找,这为我节省了精力。对于可能无效的其他方法,您可以阅读this帖子及其评论。