我想在我的验证类中交出 ItemsSource-对象,以检查用户输入(处理程序类中的值)是否可以在列表(ItemsSource)中找到
如何将组合框的项源提交到处理程序类受限组合框项目验证规则?(或我的组合框控件而不是项目源)
<ComboBox Name="bms_ComboBox
ItemsSource='{Binding Path="[BMS,ANR]"}'
SelectedValuePath="F1"
DisplayMemberPath="F1"
IsEditable="True">
<ComboBox.Text>
<Binding Path="[BMS]">
<Binding.ValidationRules>
<t:RestrictedComboBoxItemValidationRule Sender={how I can submit ItemsSource of this ComboBox to handler class???}/>
</Binding.ValidationRules>
</Binding>
</ComboBox.Text>
</ComboBox>
// ...
public class RestrictedComboBoxItemValidationRule : ValidationRule
{
public object Sender
{
get { return sender; }
set { sender = value; }
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
ValidationResult vr = ValidationResult.ValidResult;
if (comboText_inItemsSource == false) {
vr = new ValidationResult(false, "The entered value is not included in list!");
}
return vr;
}
您需要将组合框的 ItemsSource 绑定到您的 Sender-属性。由于 ValidationRule 不是 DependencyObject,因此不能只Sender
DependencyProperty。但是Josh Smith有一个很好的解决方法:http://www.codeproject.com/Articles/18678/Attaching-a-Virtual-Branch-to-the-Logical-Tree-in
我发现,有点复杂的方法。但它有效!这是这样:
我创建了一个附加属性"受限"
RestrictedProperty = DependencyProperty.RegisterAttached
("Restricted", typeof(bool), typeof(Field),
new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnChangedRestricted)));
在 OnChangedRestricted 中,我为 ComboBox.Loaded 添加了一个事件处理程序:
private static void OnChangedRestricted(DependencyObject o, DependencyPropertyChangedEventArgs e) {
Control c = o as Control;
if (c != null && (bool)e.NewValue == true) {
if (c.GetType() == typeof(ComboBox)) {
((ComboBox)c).Loaded += new RoutedEventHandler(RestrictedComboBox_Loaded);
原因是,我需要一个 vlide BindingExpression。
static void RestrictedComboBox_Loaded
(object sender, RoutedEventArgs e) {
ComboBox cb = (ComboBox)sender;
BindingExpression be = cb.GetBindingExpression
(ComboBox.TextProperty);
if (be != null) {
Binding b = be.ParentBinding;
b.ValidationRules.Add
(new RestrictedComboBoxItemValidationRule
((ComboBox)sender)); } }
这就是我在这里所做的,将验证规则添加到我的 ComboBox 的绑定中,而不是在我的 CodeBehind 中添加 XAML 代码(通过附加属性进行加密)。这是类 RestrictedComboBoxItemValidationRule(这里发生了整个监视):
public class RestrictedComboBoxItemValidationRule : ValidationRule {
private DataTable itemsSource;
private ComboBox sender;
private bool firstChance;
public RestrictedComboBoxItemValidationRule(ComboBox sender) {
this.sender = sender;
this.firstChance = true;
this.sender.LostFocus += new RoutedEventHandler(Invalidate_OnLostFocus);
this.itemsSource = this.GetItemsSource (sender.ItemsSource);
if (this.itemsSource != null) {
this.itemsSource.CaseSensitive = false; } }
public override ValidationResult Validate(object value, CultureInfo cultureInfo) {
ValidationResult result = ValidationResult.ValidResult;
if (this.sender.IsReadOnly || !this.sender.IsEditable || !this.sender.IsEnabled) {
return result; }
if (!string.IsNullOrEmpty(value as string) && this.itemsSource != null) {
DataRow[] r = this.itemsSource.Select
(this.sender.SelectedValuePath + " = '" + value.ToString() + "'");
if (r.Length == 0 && (!this.sender.IsKeyboardFocusWithin || !this.firstChance)) {
result = new ValidationResult
(false, "The entered value is not in list!"); } }
return result; }
void Invalidate_OnLostFocus(object sender, RoutedEventArgs e) {
Debug.Assert (((SWC.ComboBox)e.Source).Equals(this.sender),
"Sender-Object invalide!");
this.Invalidate(false); }
/// <param name="firstChance">true, if we want to wait for LostFocus (for our ComboBox),
/// false, if user's inputs now should be checked.
/// null, if no update of the firstChance-flag should occur</param>
private void Invalidate(bool? firstChance) {
if ((this.sender.IsEditable) && (!this.sender.IsReadOnly) &&
(!this.sender.IsKeyboardFocusWithin) && (!string.IsNullOrEmpty(this.SenderText))) {
if (firstChance.HasValue) {
this.firstChance = firstChance.Value; }
// force validation of sender-Object -> with ValidationResult Validate
this.sender.GetBindingExpression
(ComboBox.TextProperty).UpdateSource(); } }
private DataTable GetItemsSource
(object itemsSource) {
DataTable table = null;
if (itemsSource.GetType() == typeof(DataTable)) {
table = itemsSource as DataTable;
}
if (itemsSource.GetType() == typeof(DataView)) {
table = ((DataView)itemsSource).ToTable();
}
Debug.Assert(table != null,
"Unknown source type " + itemsSource.GetType ().Name);
return table; }
private string SenderText {
get { var text = (this.sender != null) ? this.sender.Text : string.Empty;
if (text == null) { text = string.Empty; }
return text.ToString().Trim(); } }
}
我的 XAML 代码是:
<ComboBox
Name="bMS_ComboBox"
ItemsSource='{Binding Path="[BMS,ANR]"}'
Text="{Binding [BMS]}"
SelectedValuePath="F1"
DisplayMemberPath="F1"
Style="{StaticResource LocalComboBoxStyle}"
IsEditable="True"
c:Field.Restricted="True">
c 是我的类字段的命名空间,附加属性受到限制:xmlns:c="clr-namespace:MyAssembly.Controls;assembly=MyAssembly.Controls"
在我的样式文件中,我有以下代码:
<Style x:Key="LocalComboBoxStyle" TargetType="{x:Type ComboBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="Images/exclamation_diamond.png"
Height="16"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Margin="0 0 2 0"/>
<Border BorderBrush="Red" BorderThickness="1" Opacity="0.6">
<Border.BitmapEffect>
<BlurBitmapEffect Radius="6"/>
</Border.BitmapEffect>
<AdornedElementPlaceholder/>
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
我知道这很复杂,但它工作正常:-)
PS:您可以在此处看到结果:在此处输入链接说明