问候
我有一个绑定到模型对象的Silverlight表单,该对象实现了INotifyDataErrorInfo,并在单击“保存”按钮时进行验证。如果模型上的某些属性返回无效,Silverlight将自动突出显示绑定的输入字段。
有没有办法将焦点设置为第一个无效字段?
更新: 有没有办法看看输入字段是否处于无效的显示状态?如果我能检测到这一点,我可以遍历我的字段并手动设置焦点。
谢谢, 马修
答案 0 :(得分:4)
您可以在视图中使用ValidationSummary来显示模型引发的所有验证错误。当您单击ValidationSummary中的错误时,将引起导致验证错误的控件。
可以在Silverlight Toolkit的samples上找到ValidationSummary的示例。
到目前为止,我没有在任何应用程序中使用ValidationSummary,因此我无法向您提供有关使用或“如何使用”的任何信息,但也许this可以帮助您
答案 1 :(得分:1)
我已经实现了这种行为。
首先,您需要订阅ViewModel ErrorsChanged
和PropertyChanged
方法。我在我的构造函数中执行此操作:
/// <summary>
/// Initializes new instance of the View class.
/// </summary>
public View(ViewModel viewModel)
{
if (viewModel == null)
throw new ArgumentNullException("viewModel");
// Initialize the control
InitializeComponent(); // exception
// Set view model to data context.
DataContext = viewModel;
viewModel.PropertyChanged += new PropertyChangedEventHandler(_ViewModelPropertyChanged);
viewModel.ErrorsChanged += new EventHandler<DataErrorsChangedEventArgs>(_ViewModelErrorsChanged);
}
然后为此事件编写处理程序:
/// <summary>
/// If model errors has changed and model still have errors set flag to true,
/// if we dont have errors - set flag to false.
/// </summary>
/// <param name="sender">Ignored.</param>
/// <param name="e">Ignored.</param>
private void _ViewModelErrorsChanged(object sender, DataErrorsChangedEventArgs e)
{
if ((this.DataContext as INotifyDataErrorInfo).HasErrors)
_hasErrorsRecentlyChanged = true;
else
_hasErrorsRecentlyChanged = false;
}
/// <summary>
/// Iterate over view model visual childrens.
/// </summary>
/// <param name="sender">Ignored.</param>
/// <param name="e">Ignored.</param>
private void _ViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if ((this.DataContext as INotifyDataErrorInfo).HasErrors)
_LoopThroughControls(this);
}
最后添加方法:
/// <summary>
/// If we have error and we haven't already set focus - set focus to first control with error.
/// </summary>
/// <remarks>Recursive.</remarks>
/// <param name="parent">Parent element.</param>
private void _LoopThroughControls(UIElement parent)
{
// Check that we have error and we haven't already set focus
if (!_hasErrorsRecentlyChanged)
return;
int count = VisualTreeHelper.GetChildrenCount(parent);
// VisualTreeHelper.GetChildrenCount for TabControl will always return 0, so we need to
// do this branch of code.
if (parent.GetType().Equals(typeof(TabControl)))
{
TabControl tabContainer = ((TabControl)parent);
foreach (TabItem tabItem in tabContainer.Items)
{
if (tabItem.Content == null)
continue;
_LoopThroughControls(tabItem.Content as UIElement);
}
}
// If element has childs.
if (count > 0)
{
for (int i = 0; i < count; i++)
{
UIElement child = (UIElement)VisualTreeHelper.GetChild(parent, i);
if (child is System.Windows.Controls.Control)
{
var control = (System.Windows.Controls.Control)child;
// If control have error - we found first control, set focus to it and
// set flag to false.
if ((bool)control.GetValue(Validation.HasErrorProperty))
{
_hasErrorsRecentlyChanged = false;
control.Focus();
return;
}
}
_LoopThroughControls(child);
}
}
}