[英]Set SelectedValue to 0 when garbage is entered in ComboBox
我有一個簡單的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中Selected Item的ID。 之后,如果用戶轉到下一個控件並返回到ComboBox,並向ComboBox輸入一些垃圾值,則ComboBox的ItemId不會更改,這意味着它不會重置為“ 0”。 因此,我的驗證失敗,並且用戶成功輸入了垃圾值。
好的,因此當ComboBox
的可編輯TextBox
中發生任何驗證錯誤時,您希望將SelectedValue
設置為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
顯示SelectedValue
的正確ItemId
,並且當用戶輸入無效文本時,所選值將重置為0。
PS:在ComboBox
輸入垃圾時,它將始終顯示驗證錯誤指示符(如上所示,為紅色邊框),並且如果將SelectedItem
數據綁定到屬性,則它將為null。 因此,如果有錯誤,您就不必關心SelectedValue
,這就是為什么我說我無法在注釋中重現該錯誤。
你真的讓我知道這個,我從來沒有意識到這個問題的存在。 我已經找到了一種解決方案,可以解決您不關心清除組合的問題。 可能有更好的方法,但是我沒有想到。 也許有人在那里有另一個解決方案。
首先,在您的對象中添加對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" >
然后在視圖后面的代碼中:
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
更改其文本時都會收到通知。 這真的是很糟糕的代碼,但是我已經耗盡了想法……
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.