2016-01-13 3 views
0

Я гораздо больше читаю здесь, в stackoverflow, чем писатель, но я отчаянно пытаюсь ответить на этот вопрос. Решения, которые я нашел до сих пор, не устраняют мою проблему: Хотя проверка правильности и отображение правильной ErrorTemplate для TextBox в следующем окне-коде работает (ViewModel за привязкой реализует INotifyDataErrorInfo), тот же самый код для TextBox переместился в пользовательский пользовательский контроль (элементы управления: LabeledTextField), не будет.ErrorTemplate on Control в UserControl

<Window x:Class="ValidationErrorTemplateTest.MainWindow" 
    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" 
    xmlns:ignore="http://www.galasoft.ch/ignore" 
    xmlns:controls="clr-namespace:ValidationErrorTemplateTest" 
    mc:Ignorable="d ignore" 
    Height="300" 
    Width="300" 
    DataContext="{Binding Main, Source={StaticResource Locator}}"> 

<Window.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
      <ResourceDictionary Source="Skins/MainSkin.xaml" /> 
     </ResourceDictionary.MergedDictionaries> 
    </ResourceDictionary> 
</Window.Resources> 

<Grid x:Name="LayoutRoot"> 
    <StackPanel> 
    <TextBox Width="100" Height="20" Text="{Binding WelcomeTitle, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged, 
     ValidatesOnNotifyDataErrors=True}" Validation.ErrorTemplate="{StaticResource validationErrorHint}" Margin="40"/> 
    <controls:LabeledTextField Value="{Binding WelcomeTitle}"/> 
    </StackPanel> 
</Grid> 

Оболочки/MainSkin.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <ControlTemplate x:Key="validationErrorHint"> 
     <DockPanel LastChildFill="True"> 
      <Border Background="Red" DockPanel.Dock="Right" Margin="5,0,0,0" Width="12" Height="12" CornerRadius="6" 
        ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}"> 
       <TextBlock Text="!" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" Foreground="White" FontSize="10"/> 
      </Border> 
      <AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center"> 
      </AdornedElementPlaceholder> 
     </DockPanel> 
    </ControlTemplate> 
</ResourceDictionary> 

Это XAML для LabeledTextField:

<UserControl x:Class="ValidationErrorTemplateTest.LabeledTextField" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     mc:Ignorable="d" 
     d:DesignHeight="30" d:DesignWidth="340"> 
<UserControl.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
      <ResourceDictionary Source="Skins/MainSkin.xaml" /> 
     </ResourceDictionary.MergedDictionaries> 
    </ResourceDictionary> 
</UserControl.Resources> 
<Grid x:Name="Root"> 
    <TextBox Width="100" Height="20" Text="{Binding Value, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged, 
     ValidatesOnNotifyDataErrors=True}" Validation.ErrorTemplate="{StaticResource validationErrorHint}"/> 
</Grid> 

и отделенного кода:

namespace ValidationErrorTemplateTest 
{ 
    public partial class LabeledTextField : UserControl 
    { 
     public LabeledTextField() 
     { 
      InitializeComponent(); 
      Root.DataContext = this; 
     } 

     public string Value 
     { 
      get { return (string)GetValue(ValueProperty); } 
      set { SetValue(ValueProperty, value); } 
     } 

     public static readonly DependencyProperty ValueProperty = 
      DependencyProperty.Register("Value", typeof(string), typeof(LabeledTextField), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); 
    } 
} 

Я прочитал о добавлении <ArdornerDecorator> -Layer, но, похоже, это не проблема. Я предполагаю, что как-то используется ErrorTemplate usercontrol, а не тот, который назначен для TextBox внутри usercontrol, но я не знаю, как это исправить. Любой намек был бы очень признателен!

ответ

0

Я был в состоянии сделать эту работу. Я просто использовал код, который вы вставили здесь, и сделал мою версию приложения.

Мои MainWindow:

<Window x:Class="ErrorTemplateNotWorking.MainWindow" 
     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" 
     xmlns:local="clr-namespace:ErrorTemplateNotWorking" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
     <ResourceDictionary> 
      <ResourceDictionary.MergedDictionaries> 
       <ResourceDictionary Source="Skins/MainSkin.xaml" /> 
      </ResourceDictionary.MergedDictionaries> 
     </ResourceDictionary> 
    </Window.Resources> 

    <Grid x:Name="LayoutRoot"> 
     <StackPanel> 
      <TextBox Width="100" Height="20" 
        Text="{Binding WelcomeTitle, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" 
        Validation.ErrorTemplate="{StaticResource validationErrorHint}" 
        Margin="40"/> 
      <local:LabeledTextField Value="{Binding WelcomeTitle, ValidatesOnDataErrors=True}" 
            Width="100" Height="20" 
            Validation.ErrorTemplate="{StaticResource validationErrorHint}" /> 
     </StackPanel> 
    </Grid> 
</Window> 

Обратите внимание, что я использую только ValidatesOnDataErrors=True в переплетах и ​​я поставил Validation.ErrorTemplate="{StaticResource validationErrorHint}" для UserControl, а также. Еще одна важная вещь - установить Width и Height для UserControl, чтобы восклицательный знак подтверждения не мог выйти за границы окна, потому что элемент управления будет просто растягиваться до его максимальной ширины без этого.

Код-за моего MainWindow:

namespace ErrorTemplateNotWorking 
{ 
    using System.Windows; 
    using System.ComponentModel; 
    using System.Runtime.CompilerServices; 
    using Annotations; 

    public class MainWindowViewModel : IDataErrorInfo, INotifyPropertyChanged 
    { 
     public string this[string columnName] 
     { 
      get { 
       if (columnName == nameof(WelcomeTitle)) 
       { 
        if (string.IsNullOrEmpty(WelcomeTitle) || WelcomeTitle.Length < 5) 
        { 
         return "Title should be at least 5 characters long"; 
        } 
       } 

       return ""; 
      } 
     } 

     public string Error => null; 

     private string _welcomeTitle; 
     public string WelcomeTitle 
     { 
      get { return _welcomeTitle; } 
      set 
      { 
       _welcomeTitle = value; 
       OnPropertyChanged(nameof(WelcomeTitle)); 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 

     [NotifyPropertyChangedInvocator] 
     protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
     { 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 

      DataContext = new MainWindowViewModel(); 
     } 
    } 
} 

Обратите внимание, что я использую некоторые ReSharper и C# 6 особенности, но суть должна быть понятна. В основном я просто устанавливаю DataContext для виртуальной машины, а в VM я реализую IDataErrorInfo с правилом проверки, что текст должен содержать не менее 5 символов.

The MainSkin.xaml - это то же самое.

И UserControl XAML:

<UserControl x:Class="ErrorTemplateNotWorking.LabeledTextField" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <UserControl.Resources> 
     <ResourceDictionary> 
      <ResourceDictionary.MergedDictionaries> 
       <ResourceDictionary Source="Skins/MainSkin.xaml" /> 
      </ResourceDictionary.MergedDictionaries> 
     </ResourceDictionary> 
    </UserControl.Resources> 
    <Grid x:Name="Root"> 
     <TextBox Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}" /> 
    </Grid> 
</UserControl> 

Здесь я даже не нужно ничего лишнего на Binding. И результат:

Result

Я надеюсь, что это помогает.

+0

большое спасибо! это сработало! Тем не менее, я чувствую разочарование в отношении wpf: я надеялся, что смогу перенести декларативный материал из всех моих текстовых полей в один шаблон usercontrol. Чтобы добавить 'ValidatesOnDataErrors = True}" Validation.ErrorTemplate = "{StaticResource validationErrorHint}", везде вокруг моего проекта довольно уродливое клонирование кода. –

Смежные вопросы