2016-12-07 8 views
1

Я пытаюсь сделать значок, всплывающую подсказку или chatbubble в поле, когда пользователь пытается ввести более длинную строку, чем поле должно принять. Я широко изучил эту тему, и я довольно изумлен, что, похоже, это нелегкое решение. Я нашел простые решения для изменения внешнего вида поля, когда вход недействителен, но ни один из них не запустит предупреждение и сохранит законное предыдущее значение в поле. Как можно добиться этого?Проверка длины в полевых триггерах error icon

+1

Это отличная идея, особенно та часть: «сохранить юридическое предыдущее значение в поле». С какой конкретной проблемой вы сталкиваетесь (подсказка: в вопросе нет вопросительного знака)? – Sinatr

+0

Итак, как ['ErrorTemplate'] (https://www.codeproject.com/tips/690130/simple-validation-in-wpf)? –

ответ

0

Правильный путь к этому - ErrorTemplate и ValidationRule.

Сначала вам понадобится ValidationRule, в вашем случае что-то, что проверяет длину строки.

public class StringLengthRule : ValidationRule 
{ 
    public int MaxLength { get; set; } 

    public override ValidationResult Validate(object value, CultureInfo cultureInfo) 
    { 
     if (((string)value).Length > MaxLength) 
      return new ValidationResult(false, "Input too long!"); 
     return new ValidationResult(true, null); 
    } 
} 

вы можете прикрепить что к связыванию вашей точки зрения, например:

<TextBox> 
    <TextBox.Text> 
     <Binding RelativeSource="{RelativeSource AncestorType=local:MainWindow}" 
       UpdateSourceTrigger="PropertyChanged" <!-- or LostFocus --> 
       Path="Text"> 
      <Binding.ValidationRules> 
       <local:StringLengthRule MaxLength="15"/> 
      </Binding.ValidationRules> 
     </Binding> 
    </TextBox.Text> 
</TextBox> 

В зависимости от вашего стиля/шаблон это будет выглядеть примерно так: (Я включил стиль и шаблон в нижней части этого ответа)

Error Template

Это будет работать для внутренних ошибок тоже. Если привязку к междунар, например:

Example 2

Вы можете использовать одни и те же Validations, чтобы проверить, если все входы действительны до закрытия диалогового окна.

public static class ValidationHelper 
{ 
    public static bool IsValid(DependencyObject obj) 
    { 
     // The dependency object is valid if it has no errors and all 
     // of its children (that are dependency objects) are error-free. 
     return !Validation.GetHasError(obj) && 
     LogicalTreeHelper.GetChildren(obj) 
     .OfType<DependencyObject>() 
     .All(IsValid); 
    } 

    public static bool ShowValidHint(DependencyObject dependencyObject) 
    { 
     if (IsValid(dependencyObject)) return true; 

     MessageBox.Show(Strings.WarningInput, Strings.InputError, MessageBoxButton.OK, MessageBoxImage.Warning); 
     return false; 
    } 
} 

Использование:

private void btnOk_Click(object sender, RoutedEventArgs e) 
{ 
    ((Button)sender).Focus(); 
    if (ValidationHelper.ShowValidHint(this)) 
     DialogResult = true; 
    else 
     // show error 
} 

Что касается сохранить юридическое предыдущее значение части. Это лучше всего сделать с помощью PropertyChangedCallback или CoerceValueCallback вашего PropertyMetadata или (если вы используете вместо этого INotifyPropertyChanged) средство настройки свойств. Я лично рекомендовал бы против этого. Если вы измените значение обратно, значение будет снова действительным, и люди, которые печатают на клавиатуре, могут даже не знать, что они сделали неправильно.

Не могу вспомнить, где у меня есть этот шаблон, но я использовал его для случаев, подобных этому целую вечность.

Шаблон управления

<ControlTemplate x:Key="TextBoxErrorTemplate"> 
    <StackPanel Orientation="Horizontal"> 
     <!-- Defines TextBox outline border and the ToolTipCorner --> 
     <Border x:Name="border" BorderThickness="1.25" BorderBrush="#FFDC000C"> 
      <Grid> 
       <Polygon x:Name="toolTipCorner" Grid.ZIndex="2" Margin="-1" Points="9,9 9,0 0,0" Fill="#FFDC000C" HorizontalAlignment="Right" 
        VerticalAlignment="Top" IsHitTestVisible="True"/> 
       <Polyline Grid.ZIndex="3" Points="10,10 0,0" Margin="-1" HorizontalAlignment="Right" StrokeThickness="1.5" 
           StrokeEndLineCap="Round" StrokeStartLineCap="Round" Stroke="White" VerticalAlignment="Top" IsHitTestVisible="True"/> 
       <AdornedElementPlaceholder x:Name="adorner"/> 
      </Grid> 
     </Border> 
     <!-- Defines the Popup --> 
     <Popup x:Name="placard" AllowsTransparency="True" PopupAnimation="Fade" Placement="Top" PlacementTarget="{Binding ElementName=toolTipCorner}" PlacementRectangle="10,-1,0,0"> 
      <!-- Used to reposition Popup when dialog moves or resizes --> 
      <Popup.Style> 
       <Style TargetType="{x:Type Popup}"> 
        <Style.Triggers> 
         <!-- Shows Popup when TextBox has focus --> 
         <DataTrigger Binding="{Binding ElementName=adorner, Path=AdornedElement.IsFocused}" Value="True"> 
          <Setter Property="IsOpen" Value="True"/> 
         </DataTrigger> 
         <!-- Shows Popup when mouse hovers over ToolTipCorner --> 
         <DataTrigger Binding="{Binding ElementName=toolTipCorner, Path=IsMouseOver}" Value="True"> 
          <Setter Property="IsOpen" Value="True"/> 
         </DataTrigger> 
         <!-- Hides Popup when window is no longer active --> 
         <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=IsActive}" Value="False"> 
          <Setter Property="IsOpen" Value="False"/> 
         </DataTrigger> 
        </Style.Triggers> 
       </Style> 
      </Popup.Style> 
      <Border x:Name="errorBorder" 
      Background="#FFDC000C" 
      Margin="0,0,8,8" 
      Opacity="1" 
      CornerRadius="4" 
      IsHitTestVisible="False" 
      MinHeight="24" 
      MaxWidth="267"> 
       <Border.Effect> 
        <DropShadowEffect ShadowDepth="4" 
          Color="Black" 
          Opacity="0.6" 
          Direction="315" 
          BlurRadius="4"/> 
       </Border.Effect> 
       <TextBlock Text="{Binding ElementName=adorner, Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}" 
       Foreground="White" 
       Margin="8,3,8,3" 
       TextWrapping="Wrap"/> 
      </Border> 
     </Popup> 
    </StackPanel> 
</ControlTemplate> 

Стиль

<Style TargetType="{x:Type TextBox}"> 
    <Setter Property="Validation.ErrorTemplate" Value="{StaticResource TextBoxErrorTemplate}"/> 
</Style> 
+0

Я постоянно удивляюсь многословию решений простых задач в WPF. Это только я? Я могу подумать, как решить эту проблему на Java с помощью нескольких строк кода (десять вершин). MVVM и WPF - это страница кода. –

+0

Мне понадобится некоторое время, чтобы выяснить, разрешает ли это проблема. Я буду обновлять после некоторой работы. Спасибо. –

+0

@ ÁrniSt.Sigurðsson Итак ... это помогло? –