如何强制验证在 UserControl 上显示
我想要带有工具提示的库存/标准红色边框验证在我的用户控件周围显示。请参阅下面的代码。我有主页和用户控件。
UserControl 有文本框和按钮。 UserControls 绑定到 Id 属性并在 TextBox 中显示此 Id。
主页有 UserControl 和 TextBox。它们绑定到 FirstValue 和 SecondValue。这两个属性都会引发错误。当我在文本框中输入/更改某些内容时 - 我看到边框和摘要。当我更改用户控件中的文本时 - 我在摘要中看到错误,但没有边框,当我单击错误时 - 它聚焦按钮,不会转到文本框。我该如何解决这个问题?我希望整个 UserControl 位于红色边框内。
MainPage XAML:
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="275" d:DesignWidth="402" xmlns:my="clr-namespace:SilverlightApplication1" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<Grid x:Name="LayoutRoot" Background="White" Width="300" HorizontalAlignment="Left">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="40" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Grid.Row="2" Margin="3" Text="{Binding SecondValue, Mode=TwoWay, NotifyOnValidationError=True}"/>
<my:TestUserControl Margin="3" Id="{Binding FirstValue, Mode=TwoWay, NotifyOnValidationError=True}"/>
<sdk:ValidationSummary Grid.Row="4" Name="validationSummary1" />
</Grid>
</UserControl>
MainPage CS
using System.Windows.Controls;
namespace SilverlightApplication1
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
public partial class MainPage : UserControl, INotifyDataErrorInfo, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
readonly Dictionary<string, List<string>> _currentErrors;
private string _firstValue;
private string _secondValue;
public MainPage()
{
InitializeComponent();
_currentErrors = new Dictionary<string, List<string>>();
_firstValue = "test1";
_secondValue = "test2";
LayoutRoot.DataContext = this;
}
public string FirstValue
{
get { return _firstValue; }
set
{
_firstValue = value;
CheckIfValueIsValid("FirstValue", value);
this.OnPropertyChanged("FirstValue");
}
}
public string SecondValue
{
get { return _secondValue; }
set
{
_secondValue = value;
CheckIfValueIsValid("SecondValue", value);
this.OnPropertyChanged("SecondValue");
}
}
public void CheckIfValueIsValid(string propertyName, string value)
{
ClearErrorFromProperty(propertyName);
AddErrorForProperty(propertyName, "Bad value");
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
return (_currentErrors.Values);
}
MakeOrCreatePropertyErrorList(propertyName);
return _currentErrors[propertyName];
}
public bool HasErrors
{
get
{
return (_currentErrors.Where(c => c.Value.Count > 0).Count() > 0);
}
}
void FireErrorsChanged(string property)
{
if (ErrorsChanged != null)
{
ErrorsChanged(this, new DataErrorsChangedEventArgs(property));
}
}
public void ClearErrorFromProperty(string property)
{
MakeOrCreatePropertyErrorList(property);
_currentErrors[property].Clear();
FireErrorsChanged(property);
}
public void AddErrorForProperty(string property, string error)
{
MakeOrCreatePropertyErrorList(property);
_currentErrors[property].Add(error);
FireErrorsChanged(property);
}
void MakeOrCreatePropertyErrorList(string propertyName)
{
if (!_currentErrors.ContainsKey(propertyName))
{
_currentErrors[propertyName] = new List<string>();
}
}
}
}
UserControl XAML:
<UserControl x:Class="SilverlightApplication1.TestUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Content="..." Grid.Column="1" Padding="10,0" />
<TextBox Text="{Binding Id, Mode=TwoWay}" />
</Grid>
</UserControl>
UserControl CS:
using System.Windows.Controls;
namespace SilverlightApplication1
{
using System.ComponentModel;
using System.Windows;
public partial class TestUserControl : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public TestUserControl()
{
InitializeComponent();
LayoutRoot.DataContext = this;
}
public string Id
{
get { return (string)base.GetValue(IdProperty); }
set
{
base.SetValue(IdProperty, value);
this.OnPropertyChanged("Id");
}
}
public static DependencyProperty IdProperty =
DependencyProperty.Register(
"Id",
typeof(string),
typeof(TestUserControl),
new PropertyMetadata(OnIdChanged));
private static void OnIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (DesignerProperties.IsInDesignTool) return;
var lookup = d as TestUserControl;
lookup.OnPropertyChanged("Id");
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
I want stock/standard red border validation with tooltip to show around my UserControl. See code below. I have main page and UserControl.
UserControl has textbox and button. UserControls binds to Id property and displays this Id inside TextBox.
Main page has UserControl and TextBox. They bound to FirstValue and SecondValue. Both properties raise error. When I type/change something in textbox - I see border and summary. When I change text in my UserControl - I see error in summary but no border and when I click on error - it focuses button, doesn't go to TextBox. How do I fix that? I want whole UserControl to be inside red border.
MainPage XAML:
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="275" d:DesignWidth="402" xmlns:my="clr-namespace:SilverlightApplication1" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<Grid x:Name="LayoutRoot" Background="White" Width="300" HorizontalAlignment="Left">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="40" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Grid.Row="2" Margin="3" Text="{Binding SecondValue, Mode=TwoWay, NotifyOnValidationError=True}"/>
<my:TestUserControl Margin="3" Id="{Binding FirstValue, Mode=TwoWay, NotifyOnValidationError=True}"/>
<sdk:ValidationSummary Grid.Row="4" Name="validationSummary1" />
</Grid>
</UserControl>
MainPage CS
using System.Windows.Controls;
namespace SilverlightApplication1
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
public partial class MainPage : UserControl, INotifyDataErrorInfo, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
readonly Dictionary<string, List<string>> _currentErrors;
private string _firstValue;
private string _secondValue;
public MainPage()
{
InitializeComponent();
_currentErrors = new Dictionary<string, List<string>>();
_firstValue = "test1";
_secondValue = "test2";
LayoutRoot.DataContext = this;
}
public string FirstValue
{
get { return _firstValue; }
set
{
_firstValue = value;
CheckIfValueIsValid("FirstValue", value);
this.OnPropertyChanged("FirstValue");
}
}
public string SecondValue
{
get { return _secondValue; }
set
{
_secondValue = value;
CheckIfValueIsValid("SecondValue", value);
this.OnPropertyChanged("SecondValue");
}
}
public void CheckIfValueIsValid(string propertyName, string value)
{
ClearErrorFromProperty(propertyName);
AddErrorForProperty(propertyName, "Bad value");
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
return (_currentErrors.Values);
}
MakeOrCreatePropertyErrorList(propertyName);
return _currentErrors[propertyName];
}
public bool HasErrors
{
get
{
return (_currentErrors.Where(c => c.Value.Count > 0).Count() > 0);
}
}
void FireErrorsChanged(string property)
{
if (ErrorsChanged != null)
{
ErrorsChanged(this, new DataErrorsChangedEventArgs(property));
}
}
public void ClearErrorFromProperty(string property)
{
MakeOrCreatePropertyErrorList(property);
_currentErrors[property].Clear();
FireErrorsChanged(property);
}
public void AddErrorForProperty(string property, string error)
{
MakeOrCreatePropertyErrorList(property);
_currentErrors[property].Add(error);
FireErrorsChanged(property);
}
void MakeOrCreatePropertyErrorList(string propertyName)
{
if (!_currentErrors.ContainsKey(propertyName))
{
_currentErrors[propertyName] = new List<string>();
}
}
}
}
UserControl XAML:
<UserControl x:Class="SilverlightApplication1.TestUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Content="..." Grid.Column="1" Padding="10,0" />
<TextBox Text="{Binding Id, Mode=TwoWay}" />
</Grid>
</UserControl>
UserControl CS:
using System.Windows.Controls;
namespace SilverlightApplication1
{
using System.ComponentModel;
using System.Windows;
public partial class TestUserControl : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public TestUserControl()
{
InitializeComponent();
LayoutRoot.DataContext = this;
}
public string Id
{
get { return (string)base.GetValue(IdProperty); }
set
{
base.SetValue(IdProperty, value);
this.OnPropertyChanged("Id");
}
}
public static DependencyProperty IdProperty =
DependencyProperty.Register(
"Id",
typeof(string),
typeof(TestUserControl),
new PropertyMetadata(OnIdChanged));
private static void OnIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (DesignerProperties.IsInDesignTool) return;
var lookup = d as TestUserControl;
lookup.OnPropertyChanged("Id");
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
![扫码二维码加入Web技术交流群](/public/img/jiaqun_03.jpg)
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为了使您的示例正常工作,您应该从
TestUserControl.xaml.cs
文件中删除所有代码并修复绑定。像这样:后面是空代码:
接下来,你的另一个问题
可以通过绑定到
HasError
属性来实现。根据您的代码,它看起来是这样的:我添加了红色的
Border
元素,当HasError
属性设置为 true 时,该元素变得可见。但是您应该在代码中的某个位置调用OnPropertyChanged("HasError")
。另一种方法:创建自定义控件而不是 UserControl。
我已经发布了过多的描述如何在自定义控件中实现验证作为 这个关于验证的问题。
我可以做出更具体的答案,但是您应该通过将视图模型与视图分离来修复帖子中的代码,因为现在很难根据当前代码实现某些内容。
检查我关于使用 INotifyDataErrorInfo 实现验证的帖子: WPF 和 Silverlight验证。
或者您可以直接下载我的验证类。
之后代码会简单得多,我将能够帮助您解决更复杂的问题。
To make your example work, you should remove all the code from the
TestUserControl.xaml.cs
file and fix bindings. Like this:And empty code behind:
Next, your another question
It can be achieved by binding to the
HasError
property. According to your code it will look so:I've added the red
Border
element which becomes visible when theHasError
property is set to true. But you should call theOnPropertyChanged("HasError")
somewhere in your code.Another way: to create a custom control instead of UserControl.
I've posted excessive description how to implement validation in custom controls as the answer to this question about validation.
I can make a more concrete answer, but you should fix the code in your post by separating view model from view, because now it is difficult to implement something based on current code.
Check my post about implementation of validation using INotifyDataErrorInfo: WPF and Silverlight Validation.
Or you can download my validation classes directly.
After that the code will be much simplier, and I will be able to help you with more complex questions.
更改
更改为
Change
to