C# 使用MVVM将出错的WPF文本框滚动到视图中
我有一个控件,最基本的级别是一个ScrollViewer,它有一个StackPanel(方向=垂直),里面有很多文本框C# 使用MVVM将出错的WPF文本框滚动到视图中,c#,wpf,mvvm,C#,Wpf,Mvvm,我有一个控件,最基本的级别是一个ScrollViewer,它有一个StackPanel(方向=垂直),里面有很多文本框 <ScrollViewer> <StackPanel x:Name="MyStackPanel" Orientation="Vertical"> <TextBox Text="{Binding PropertyA, ValidatesOnDataErrors=True}" />
<ScrollViewer>
<StackPanel x:Name="MyStackPanel"
Orientation="Vertical">
<TextBox Text="{Binding PropertyA, ValidatesOnDataErrors=True}" />
<TextBox Text="{Binding PropertyB, ValidatesOnDataErrors=True}" />
<TextBox Text="{Binding PropertyC, ValidatesOnDataErrors=True}" />
<!-- ... -->
<TextBox Text="{Binding PropertyX, ValidatesOnDataErrors=True}" />
<TextBox Text="{Binding PropertyY, ValidatesOnDataErrors=True}" />
<TextBox Text="{Binding PropertyZ, ValidatesOnDataErrors=True}" />
</StackPanel>
</ScrollViewer>
当出现错误时,我想将出现错误的控件滚动到视图中。例如,如果用户位于列表的顶部,并且绑定到PropertyX的文本框出错,那么我希望ScrollViewer滚动到它
目前,我从ScrollViewer继承并添加了以下方法
public void ScrollErrorTextBoxIntoView()
{
var controlInError = GetFirstChildControlWithError(this);
if (controlInError == null)
{
return;
}
controlInError.BringIntoView();
}
}
public Control GetFirstChildControlWithError(DependencyObject parent)
{
if (parent == null)
{
return null;
}
Control findChildInError = null;
var children = LogicalTreeHelper.GetChildren(parent).OfType<DependencyObject>();
foreach (var child in children)
{
var childType = child as Control;
if (childType == null)
{
findChildInError = GetFirstChildControlWithError(child);
if (findChildInError != null)
{
break;
}
}
else
{
var frameworkElement = child as FrameworkElement;
// If the child is in error
if (Validation.GetHasError(frameworkElement))
{
findChildInError = (Control)child;
break;
}
}
}
return findChildInError;
}
public void ScrollErrorTextBoxIntoView()
{
var controlInError=GetFirstChildControlWithError(此);
如果(controlInError==null)
{
返回;
}
controlInError.BringIntoView();
}
}
公共控件GetFirstChildControlWithError(DependencyObject父对象)
{
如果(父项==null)
{
返回null;
}
控件findChildInError=null;
var children=logicaltreeheloper.GetChildren(parent).OfType();
foreach(儿童中的儿童变量)
{
var childType=作为控件的子对象;
if(childType==null)
{
findChildInError=GetFirstChildControlWithError(子级);
if(findChildInError!=null)
{
打破
}
}
其他的
{
var frameworkElement=作为frameworkElement的子级;
//如果孩子出错了
if(Validation.GetHasError(frameworkElement))
{
findChildInError=(控制)子级;
打破
}
}
}
返回findChildiner错误;
}
我很难让它正常工作。在我看来,我有两个选择
注意。GetFirstChildControlWithError是根据这个问题改编的 在以下假设下工作:
- 视图模型正确地实现了
和INotifyPropertyChanged
IDataErrorInfo
- 当至少有一个属性存在验证错误时,
属性不为nullIDataErrorInfo.Error
- 您希望保持严格的M-VM分离;因此,ViewModel不应调用仅用于调整视图的方法李>
ScrollViewer
下面是一个示例实现:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
public class ScrollToFirstInvalidElementBehavior : Behavior<ScrollViewer>
{
protected override void OnAttached()
{
ResetEventHandlers(null, AssociatedObject.DataContext);
AssociatedObject.DataContextChanged += OnDataContextChanged;
}
protected override void OnDetaching()
{
AssociatedObject.DataContextChanged -= OnDataContextChanged;
}
private void OnDataContextChanged(object sender,
DependencyPropertyChangedEventArgs e)
{
ResetEventHandlers(e.OldValue, e.NewValue);
}
private void ResetEventHandlers(object oldValue, object newValue)
{
var oldContext = oldValue as INotifyPropertyChanged;
if (oldContext != null)
{
oldContext.PropertyChanged -= OnDataContextPropertyChanged;
}
var newContext = newValue as INotifyPropertyChanged;
if (newContext is IDataErrorInfo)
{
newContext.PropertyChanged += OnDataContextPropertyChanged;
}
}
private void OnDataContextPropertyChanged(object sender,
PropertyChangedEventArgs e)
{
var dataError = (IDataErrorInfo) sender;
if (!string.IsNullOrEmpty(dataError.Error))
{
var controlInError = GetFirstChildControlWithError(AssociatedObject);
if (controlInError != null)
{
controlInError.BringIntoView();
}
}
}
private Control GetFirstChildControlWithError(ScrollViewer AssociatedObject)
{
//...
}
}
使用System.ComponentModel;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Interactive;
公共类ScrollToFirstInvalidElementBehavior:Behavior
{
受保护的覆盖无效附加()
{
ResetEventHandlers(null,AssociatedObject.DataContext);
AssociatedObject.DataContextChanged+=OnDataContextChanged;
}
附加时受保护的覆盖无效()
{
AssociatedObject.DataContextChanged-=OnDataContextChanged;
}
私有void OnDataContextChanged(对象发送方,
DependencyPropertyChangedEventArgs(附件e)
{
ResetEventHandlers(e.OldValue、e.NewValue);
}
私有void resetEventHandler(对象oldValue、对象newValue)
{
var oldContext=作为INotifyPropertyChanged的oldValue;
if(oldContext!=null)
{
oldContext.PropertyChanged-=OnDataContextPropertyChanged;
}
var newContext=INotifyPropertyChanged的新值;
if(新上下文为IDataErrorInfo)
{
newContext.PropertyChanged+=OnDataContextPropertyChanged;
}
}
私有void OnDataContextPropertyChanged(对象发送方,
PropertyChangedEventArgs(e)
{
var dataError=(IDataErrorInfo)发送方;
如果(!string.IsNullOrEmpty(dataError.Error))
{
var controlInError=GetFirstChildControlWithError(关联对象);
如果(controlInError!=null)
{
controlInError.BringIntoView();
}
}
}
私有控件GetFirstChildControlWithError(ScrollViewer关联对象)
{
//...
}
}
在以下假设下工作:
- 视图模型正确地实现了
和INotifyPropertyChanged
IDataErrorInfo
- 当至少有一个属性存在验证错误时,
属性不为nullIDataErrorInfo.Error
- 您希望保持严格的M-VM分离;因此,ViewModel不应调用仅用于调整视图的方法李>
ScrollViewer
下面是一个示例实现:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
public class ScrollToFirstInvalidElementBehavior : Behavior<ScrollViewer>
{
protected override void OnAttached()
{
ResetEventHandlers(null, AssociatedObject.DataContext);
AssociatedObject.DataContextChanged += OnDataContextChanged;
}
protected override void OnDetaching()
{
AssociatedObject.DataContextChanged -= OnDataContextChanged;
}
private void OnDataContextChanged(object sender,
DependencyPropertyChangedEventArgs e)
{
ResetEventHandlers(e.OldValue, e.NewValue);
}
private void ResetEventHandlers(object oldValue, object newValue)
{
var oldContext = oldValue as INotifyPropertyChanged;
if (oldContext != null)
{
oldContext.PropertyChanged -= OnDataContextPropertyChanged;
}
var newContext = newValue as INotifyPropertyChanged;
if (newContext is IDataErrorInfo)
{
newContext.PropertyChanged += OnDataContextPropertyChanged;
}
}
private void OnDataContextPropertyChanged(object sender,
PropertyChangedEventArgs e)
{
var dataError = (IDataErrorInfo) sender;
if (!string.IsNullOrEmpty(dataError.Error))
{
var controlInError = GetFirstChildControlWithError(AssociatedObject);
if (controlInError != null)
{
controlInError.BringIntoView();
}
}
}
private Control GetFirstChildControlWithError(ScrollViewer AssociatedObject)
{
//...
}
}
使用System.ComponentModel;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Interactive;
公共类ScrollToFirstInvalidElementBehavior:Behavior
{
受保护的覆盖无效附加()
{
ResetEventHandlers(空,关联到