WPF ValidationErrorTemplate样式的动态位置

本文关键字:动态 位置 样式 ValidationErrorTemplate WPF | 更新日期: 2023-09-27 18:20:39

因此,我为每个控件和ValidationErrorTemplate都获得了一个巨大的样式模板字典。问题是,当控件上方没有位置时,我们应该在控件下方显示验证错误。基本用于窗口顶部的控件。对于窗口底部的控件,验证应显示在控件上方。

由于它是一个定义了所有样式的资源字典,因此没有代码隐藏,而且也不可能有数据绑定

一个想法是确定AdornedElementPlaceholder的位置并分别隐藏/显示模板。但我在XAML中找不到任何解决方案。

    <ControlTemplate x:Key="ValidationErrorTemplate">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid Grid.Row="1">
                <Border>
                    <AdornedElementPlaceholder />
                </Border>                
            </Grid>
            <AdornerDecorator Grid.Row="????">
                <Border >
                    <!-- some style comes here ...  -->
                </Border>
            </AdornerDecorator>
        </Grid>
    </ControlTemplate>

网格。Row="???"应为0或1,具体取决于控件的顶部。

WPF ValidationErrorTemplate样式的动态位置

有两个独立的模板(一个与另一个相对),并将一个用于顶部的项目,另一个用于底部的项目,无论哪个对象包含您所说的控件,都会认为合适。

所以我终于找到了解决方案:附加属性。我创建了一个附加属性,并在属性更改回调方法上订阅了AdornerDecorator.Loaded事件。在该方法中,您可以检查实际位置,并在需要时更改属性。

【示例代码片段,在实际源代码中,由于代码特定问题,它更多地是外包和重新检查的】

private static void DecoratorLoaded(object obj, RoutedEventArgs e)
{
     var decorator = obj as Decorator;
     if (decorator != null && decorator.IsVisible)
     {
        // get the position
        Point renderedLocation = decorator.TranslatePoint(new Point(0, 0), Application.Current.MainWindow);
        if (renderedLocation != new Point(0, 0))
        {
           // check width
           var maxAllowedWidth = Application.Current.MainWindow.ActualWidth - renderedLocation.X - 40;               
           decorator.SetValue(FrameworkElement.MaxWidthProperty, maxAllowedWidth);
           // check place above the control
           var isEnoughPlaceAbove = renderedLocation.Y > decorator.ActualHeight + 10;
           decorator.SetValue(Grid.RowProperty, isEnoughPlaceAbove ? 0 : 2);
           // invalidate to re-render
           decorator.InvalidateVisual();               
        }
     }
}

您需要使用Loaded事件来确保renderLocation将为您提供实际位置,而不是其他位置(例如零或一些相对位置)。

最后,您需要将附加的属性附加到XAML中的装饰器:

<AdornerDecorator Behaviors:AdornerPositionCalculator.AllowDynamicPosition="True">
  <!-- custom style here -->
</AdornerDecorator>