gpt4 book ai didi

c# - 使用 MVVM 将错误的 WPF 文本框滚动到 View 中

转载 作者:行者123 更新时间:2023-12-03 10:37:37 26 4
gpt4 key购买 nike

我有一个控件,它最基本的级别是一个带有 StackPanel(方向=垂直)的 ScrollViewer,其中有很多 TextBox。

<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>

当错误发生时,我想将任何有错误的控件滚动到 View 中。例如,如果用户位于列表顶部并且绑定(bind)到 PropertyX 的 TextBox 出错,那么我希望 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;
}

我很难让它正常工作。在我看来,我有两个选择。
  • 尝试让 ViewModel 执行 ScrollErrorTextBoxIntoView 方法。我不确定最好的方法是什么。我试图设置一个属性并从中采取行动,但它似乎不正确(而且它无论如何都没有用)
  • 让控件以独立的方式进行。这将要求我的 ScrollViewer (递归地)监听其子项,并在其中任何一个处于错误状态时调用该方法。

  • 所以我的问题是:
  • 这两个选项中哪一个更好,您将如何实现它们?
  • 有没有更好的方法来做到这一点? (行为等?)它必须是 MVVM。

  • 注意。 GetFirstChildControlWithError 改编自这个问题。 How can I find WPF controls by name or type?

    最佳答案

    在以下假设下工作:

  • 您的 View 模型实现了 INotifyPropertyChanged正确和IDataErrorInfo
  • IDataErrorInfo.Error当至少一个属性存在验证错误时,属性不为空。
  • 您想保持严格的 M-VM 分离;因此 ViewModel 不应调用仅用于调整 View 的方法。

  • 基本上,您想监听 DataContext 属性更改并找出是否存在 DataError。

    如果你看 behaviors , 你可以在不继承 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)
    {
    //...
    }
    }

    关于c# - 使用 MVVM 将错误的 WPF 文本框滚动到 View 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19451529/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com