【发布时间】:2011-10-27 21:44:06
【问题描述】:
我希望在我的 UserControl 周围显示带有工具提示的库存/标准红色边框验证。请参阅下面的代码。我有主页和 UserControl。
UserControl 有文本框和按钮。 UserControls 绑定到 Id 属性并在 TextBox 中显示此 Id。
主页有 UserControl 和 TextBox。它们绑定到 FirstValue 和 SecondValue。这两个属性都会引发错误。当我在文本框中输入/更改某些内容时 - 我看到了边框和摘要。当我在 UserControl 中更改文本时 - 我在摘要中看到错误但没有边框,当我点击错误时 - 它聚焦按钮,不会转到 TextBox。我该如何解决?我希望整个 UserControl 都在红色边框内。
主页 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>
主页 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>();
}
}
}
}
用户控件 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>
用户控制 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));
}
}
}
}
【问题讨论】:
-
错误检查发生在对象内部,该对象设置为控件的
DataContext属性。据我所知,您将this设置为TestUserControl用户控件的DataContext,但您尚未向该控件添加验证。代码中还有许多其他错误,如果使用 MVVM 模式,可以摆脱它们。无论如何,我会尝试启动你的代码,看看我能做什么。 -
@vorrtex 示例只是一次性代码——我只是为了这个示例快速复制/粘贴了接口实现,以便您可以运行它。在现场项目中,它是 MVVM + PRISM
-
@vorrtex 另外,请参阅我对 Ekk 的回复。为什么我需要在 UserControl 中进行验证?我正在验证 Id 并且我希望 UserControl 被整体验证。因此,作为另一个示例,我可以实现 3 个文本框作为 UserControl 来输入电话号码。然后,我希望 Validation 再次在 Whole UserControl 上工作,并在所有 3 个框(一个矩形)周围显示红色边框。现在我得到了正确的验证,我只是没有得到 UI。同样,我将 UserControl 视为我的 UI 元素,我的主窗体将其视为任何其他控件。
标签: c# silverlight validation inotifydataerrorinfo