我有一个简单的ComboBox,如下所示:
<ComboBox ItemsSource="{DynamicResource ItemsCompColl}"
TextSearch.TextPath="ItemName"
SelectedValue="{Binding ItemId, UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True}" SelectedValuePath="ItemId"
Grid.IsSharedSizeScope="True">
........................
</ComboBox>
效果很好。现在,我正在使用在SelectedValue中绑定的ItemId属性来检查用户是否从comboBox中选择了适当的项目。
的问题:
当用户从ComboBox中选择一个值时,ItemId属性将设置为ComboBox中所选项的Id。之后如果用户进入下一个Control并返回ComboBox并向ComboBox输入一些垃圾值,则ComboBox的ItemId不会改变,我的意思是它没有重置为&#34; 0&#34;。因此,我的验证失败,用户成功输入垃圾值。
答案 0 :(得分:2)
好的,所以当SelectedValue
的可编辑TextBox
中存在任何验证错误时,您希望将ComboBox
设置为0。您需要检查Text
的验证结果,然后在验证失败时将SelectedValue
重置为0。
以下是您的工作示例:
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<ComboBox ItemsSource="{Binding ComboboxItems}"
IsEditable="True" DisplayMemberPath="ItemName"
Text="{Binding SelectedName, ValidatesOnDataErrors=True}"
SelectedValue="{Binding SelectedID, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="ItemId"
Grid.IsSharedSizeScope="True">
</ComboBox>
<TextBox Text="{Binding SelectedID,UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</Grid>
</Window>
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
MyViewModel mvm;
public MainWindow()
{
InitializeComponent();
mvm = new MyViewModel()
{
ComboboxItems = new ObservableCollection<ComboItem>()
{
new ComboItem{ItemName="item1",ItemId=1},
new ComboItem{ItemName="item2",ItemId=2},
new ComboItem{ItemName="item3",ItemId=3}
},
};
this.DataContext = mvm;
}
}
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, e);
}
}
protected void RaisePropertyChanged(String propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
}
public class ComboItem : ObservableObject
{
private string _itemname;
private int _itemid;
public string ItemName
{
get
{
return _itemname;
}
set
{
_itemname = value;
RaisePropertyChanged("ItemName");
}
}
public int ItemId
{
get { return _itemid; }
set
{
_itemid = value;
RaisePropertyChanged("ItemId");
}
}
}
public class MyViewModel : ObservableObject, IDataErrorInfo
{
private int _selectedid;
private string _selectedname;
public ObservableCollection<ComboItem> ComboboxItems
{
get;
set;
}
public int SelectedID
{
get { return _selectedid; }
set
{
if (_selectedid != value)
{
_selectedid = value;
RaisePropertyChanged("SelectedID");
}
}
}
public string SelectedName
{
get { return _selectedname; }
set
{
if (_selectedname != value)
{
_selectedname = value;
RaisePropertyChanged("SelectedName");
}
}
}
public string Error
{
get { return this[SelectedName]; }
}
public string this[string columnName]
{
get {
switch (columnName)
{
case "SelectedName":
{
if (SelectedName!=null && ComboboxItems.Count(x => x.ItemName == SelectedName) == 0)
{
//reset selected value to 0
this.SelectedID = 0;
return "Invalid selection";
}
break;
}
}
return null;
}
}
}
}
结果:
当用户输入有效文本(例如item1)时,下方Textbox
会显示ItemId
的正确SelectedValue
,当用户输入无效文字时,所选值将重置为0
PS:当在ComboBox
中输入垃圾时,它将始终显示验证错误指示符(如上所示的红色边框),如果您将SelectedItem
数据绑定到属性,则它将为null 。因此,如果出现错误,您不应该关心SelectedValue
,这就是为什么我说我无法在评论中重现错误。
答案 1 :(得分:2)
你真的让我知道这一点,我从未意识到存在这个问题。我找到了一个解决方案,它可以帮助您清除焦点上的组合。可能有更好的方法,但我无法思考。也许有人在那里有另一个解决方案。
首先,在您的proyect中添加对Windows.System.Interactivity
的引用,并将其添加到您的XAML中:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
然后,将此代码添加到组合框:
<ComboBox ItemsSource="{DynamicResource ItemsCompColl}"
TextSearch.TextPath="ItemName" x:Name="cbItems"
SelectedValue="{Binding ItemId, UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True}" SelectedValuePath="ItemId"
Grid.IsSharedSizeScope="True">
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotMouseCapture">
<i:InvokeCommandAction Command="{Binding ClearCombo}"
CommandParameter="{Binding ElementName=cbItems}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
最后,让我们在ouw View Model:
中创建命令RelayCommand<System.Windows.Controls.ComboBox> _clearCombo;
public ICommand ClearCombo
{
get
{
if (_clearCombo == null)
{
_clearCombo = new RelayCommand<System.Windows.Controls.ComboBox>(this.ClearComboCommandExecuted,
param => this.ClearComboCommandCanExecute());
}
return _clearCombo;
}
}
private bool ClearComboCommandCanExecute()
{
return true;
}
private void ClearComboCommandExecuted(System.Windows.Controls.ComboBox cb)
{
cb.Text = "";
}
希望这有助于解决您的问题。
修改强>
好的,在@XAMlMAX评论之后,我认为他是对的,这可以很容易地在Code Behind中完成,并且可能在MVVM模式中更好。只需在组合框中添加一个事件处理程序即可捕获GotMouseCapture
:
<ComboBox ItemsSource="{DynamicResource ItemsCompColl}"
TextSearch.TextPath="ItemName" x:Name="cbItems"
SelectedValue="{Binding ItemId, UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True}" SelectedValuePath="ItemId"
Grid.IsSharedSizeScope="True"
GotMouseCapture="cbItems_GotMouseCapture" >
然后在View的代码背后:
private void cbItems_GotMouseCapture(object sender, MouseEventArgs e)
{
((ComboBox)sender).Text = "";
}
修改2
嗯,最后一个难以理解的想法来解决它。我根本不喜欢它,但也许它可以解决你的问题。
首先,您必须订阅TextBoxBase.TextChanged
事件:
<ComboBox ItemsSource="{DynamicResource ItemsCompColl}"
TextSearch.TextPath="ItemName" x:Name="cbItems"
SelectedValue="{Binding ItemId, UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True}" SelectedValuePath="ItemId"
Grid.IsSharedSizeScope="True"
TextBoxBase.TextChanged="cbItems_TextChanged" >
然后在代码后面添加此代码:
private void cbItems_TextChanged(object sender, TextChangedEventArgs e)
{
string text = ((ComboBox)sender).Text;
((YourViewModel)this.DataContext).ItemId= text;
}
这样,您确保ComboBox
更改其文字时,您会收到相关通知。这是非常可怕的代码,但我已经没有想法......