В общем есть такой TextBox к которому добавлены ValidationRules
Вопрос в том как правильно вернуть в модель(привязать к модели) флаг о наличии ошибки (bool HasError)?
Vmin это float и сожалению есть ограничение средствами только 4 frameworka.
<TextBox
Margin="5,0,0,0"
MaxLength="7"
TextWrapping="Wrap"
VerticalContentAlignment="Center"
VerticalAlignment="Stretch"
Style="{StaticResource textBoxStyle}"
Language="ru-RU" Height="20">
<Binding Path="Vmin"
TargetNullValue=""
ValidatesOnExceptions="True"
NotifyOnValidationError="True"
UpdateSourceTrigger="PropertyChanged"
NotifyOnSourceUpdated="True"
StringFormat="#0.###"
Converter="{StaticResource TextToFloat}"
>
<Binding.ValidationRules>
<ExceptionValidationRule/>
<rules:DoubleValidationRule MinValue="0.000" MaxValue="9999.999"/>
</Binding.ValidationRules>
</Binding>
</TextBox>
в ресурсах описан стиль который рисует рамку и выводит Tooltip
<Style x:Key="textBoxStyle" TargetType="{x:Type TextBox}">
<Style.Resources>
<Style x:Key="{x:Type ToolTip}" TargetType="{x:Type ToolTip}">
<Setter Property="Background" Value="Red"/>
<Setter Property="Foreground" Value="White"/>
</Style>
</Style.Resources>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<TextBlock Margin="0 0 5 0"
Text="!"
FontSize="14"
FontWeight="Bold"
Foreground="Red"/>
<Border BorderBrush="Red" BorderThickness="2" >
<AdornedElementPlaceholder x:Name="adornedElement"/>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="VerticalAlignment" Value="Center"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
модель не привожу так как понятно что её надо будет править возможно полностью переделывать
да и не думаю что особо поможет... (хотя мог ошибаться)
фрагмент
float _Vmin;
public float Vmin
{
get { return _Vmin; }
set
{
_Vmin = value;
if (!_prev_Vmin.Equals(_Vmin))
{
HasHasChangedArray[_Vmin_] = true;
HasChanged = true;
}
else
{
HasHasChangedArray[_Vmin_] = false;
HasChanged = isChangedArray();
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Vmin)));
}
}
Как вариант, можно использовать присоединенные свойства (attached property). Для этого напишем небольшой класс-помощник.
internal class TextBoxValidationHelper
{
public static readonly DependencyProperty HasErrorProperty =
DependencyProperty.RegisterAttached("HasError", typeof(bool), typeof(TextBoxValidationHelper),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, null, CoerceHasError));
public static bool GetHasError(DependencyObject d) =>
(bool)d.GetValue(HasErrorProperty);
public static void SetHasError(DependencyObject d, bool value) =>
d.SetValue(HasErrorProperty, value);
private static object CoerceHasError(DependencyObject d, object baseValue)
{
bool ret = (bool)baseValue;
if (BindingOperations.IsDataBound(d, HasErrorProperty))
{
if (GetHasErrorDescriptor(d) == null)
{
DependencyPropertyDescriptor desc = DependencyPropertyDescriptor.FromProperty(Validation.HasErrorProperty, d.GetType());
desc.AddValueChanged(d, OnHasErrorChanged);
SetHasErrorDescriptor(d, desc);
ret = Validation.GetHasError(d);
}
}
else
{
if (GetHasErrorDescriptor(d) != null)
{
DependencyPropertyDescriptor desc = GetHasErrorDescriptor(d);
desc.RemoveValueChanged(d, OnHasErrorChanged);
SetHasErrorDescriptor(d, null);
}
}
return ret;
}
private static readonly DependencyProperty HasErrorDescriptorProperty =
DependencyProperty.RegisterAttached("HasErrorDescriptor", typeof(DependencyPropertyDescriptor), typeof(TextBoxValidationHelper));
private static DependencyPropertyDescriptor GetHasErrorDescriptor(DependencyObject d) =>
d.GetValue(HasErrorDescriptorProperty) as DependencyPropertyDescriptor;
private static void SetHasErrorDescriptor(DependencyObject d, DependencyPropertyDescriptor value) =>
d.SetValue(HasErrorDescriptorProperty, value);
private static void OnHasErrorChanged(object sender, EventArgs e)
{
if (sender is DependencyObject d)
d.SetValue(HasErrorProperty, d.GetValue(Validation.HasErrorProperty));
}
}
В разметке у вашего TextBox добавляем:
<TextBox helpers:TextBoxValidationHelper.HasError="{Binding HasError}">
. . .
</TextBox>
При этом, не забудьте описать соответствующее пространство имён:
<UserControl x:Class="..." xmlns:helpers="clr-namespace:...">
Ну и последнее, описываем соответствующее свойство в VM:
private bool hasError = false;
public bool HasError
{
get => this.hasError;
set => SetProperty(ref this.hasError, value);
}
Для справки, SetProperty- часть реализации INotifyPropertyChanged:
protected void SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (!Equals(storage, value))
{
storage = value;
OnPropertyChanged(propertyName);
}
}
Всем спасибо большое. Вот картинка того что получилось
При ошибке в любом из полей ввода выставляется флаг наличия ошибки.
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости