Как отобразить множественную ошибку IDataErrorInfo во всплывающей подсказке WPF DataGridTextColumn для наведенной ячейки?
Я могу отобразить ошибку проверки для одной конкретной ячейки в сетке данных, но я не знаю, как это сделать, если существует более одной ошибки проверки. Например, у меня есть десять столбцов, и есть ошибки проверки в двух или более ячейках.
В настоящее время я определил стиль в отдельном файле, включенном в App.xaml как ResourceDictionary.
Стиль:
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="FontSize" Value="16"/>
<Setter Property="FontFamily" Value="ArialMT"/>
<Setter Property="Height" Value="24"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="ValidationErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<Ellipse Width="12" Height="12" Fill="Red" Stroke="Black" StrokeThickness="0.5"/>
<TextBlock FontWeight="Bold" Padding="4,0,0,0" Margin="0" VerticalAlignment="Top" Foreground="White" Text="!" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<!--<DataTrigger Binding="{Binding Path=(Validation.HasError), RelativeSource={RelativeSource AncestorType=DataGridRow}}" Value="true" >-->
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="IsEnabled" Value="True" />
<!--<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors).Currentitem.ErrorContent}"/>-->
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="cycleErrStyle" TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(Validation.HasError), RelativeSource={RelativeSource AncestorType=DataGridRow}}" Value="true" >
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
Модельный класс:
public class RawTag : IDataErrorInfo, INotifyPropertyChanged
{
private readonly int hash;
private string tagName;
private string cycle;
private string source;
public RawTag()
{
hash = GetHashCode();
}
public RawTag(string tagName, string cycle, string source)
{
TagName = tagName;
Cycle = cycle;
Source = source;
hash = GetHashCode();
}
public string TagName
{
get => tagName;
set
{
if (value == tagName) return;
tagName = value;
OnPropertyChanged();
}
}
// should be an integer but any entered value shall be accepted
public string Cycle
{
get => cycle;
set
{
if (value.Equals(cycle))
{
return;
}
cycle = value;
OnPropertyChanged();
}
}
public string Source
{
get => source;
set
{
if (value == source) return;
source = value;
OnPropertyChanged();
}
}
string IDataErrorInfo.Error
{
get
{
StringBuilder error = new StringBuilder();
if (string.IsNullOrEmpty(TagName))
{
error.Append("Name cannot be null or empty");
}
if (!int.TryParse(Cycle.ToString(), out int i))
{
error.Append("Cycle should be an integer value.");
}
return error.ToString();
}
}
string IDataErrorInfo.this[string columnName]
{
get
{
// apply property level validation rules
if (columnName == "TagName")
{
if (string.IsNullOrEmpty(TagName))
return "Name cannot be null or empty";
}
if (columnName == "Cycle")
{
if (!int.TryParse(Cycle.ToString(), out int i))
return "Cycle should be an integer value.";
}
if (columnName == "Source")
{
if (string.IsNullOrEmpty(Source))
return "Source must not be empty";
}
return "";
}
}
public override string ToString()
{
return "TagName: " + TagName + " Cycle: " + Cycle + " Source: " + Source;
}
public bool IsDirty()
{
return hash != GetHashCode();
}
protected bool Equals(RawTag other)
{
return string.Equals(TagName, other.TagName) && string.Equals(Cycle, other.Cycle) && string.Equals(Source, other.Source);
//return string.Equals(TagName, other.TagName) && Cycle == other.Cycle && string.Equals(Source, other.Source);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((RawTag)obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = (TagName != null ? TagName.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (Cycle != null ? Cycle.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (Source != null ? Source.GetHashCode() : 0);
return hashCode;
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Мой класс проверки:
public class CycleValidationRule : ValidationRule
{
public override ValidationResult Validate(object value,
System.Globalization.CultureInfo cultureInfo)
{
BindingGroup group = (BindingGroup)value;
StringBuilder error = null;
foreach (var item in group.Items)
{
IDataErrorInfo info = item as IDataErrorInfo;
if (info != null)
{
if (!string.IsNullOrEmpty(info.Error))
{
if (error == null)
{
error = new StringBuilder();
}
error.Append((error.Length != 0 ? ", " : "") + info.Error);
}
}
}
if (error != null)
return new ValidationResult(false, error.ToString());
else
return new ValidationResult(true, "");
}
}
После проверки я хочу, чтобы неисправные ячейки были выделены, и при наведении курсора на неисправную ячейку во всплывающей подсказке должно отображаться только сообщение об ошибке для этой конкретной ячейки / поля проверки.
Обновление 2019-01-17:
Должен быть способ объединить IDataErrorInfo
с ValidationRules
таким образом, что сообщения об ошибках от IDataErrorInfo
попадает в ValidationRule
(который в настоящее время работает хорошо), где я могу объединить сообщения об ошибках с сообщениями от ValidationRule
и предложите эту сумму сообщений об ошибках GUI (WPF). ... но только сообщения об ошибках от IDataErrorInfo
отображаются во всплывающей подсказке.
1 ответ
IDataErrorInfo
не поддерживает несколько ошибок проверки для каждого свойства. Более новый интерфейс INotifyDataErrorInfo, который был представлен в.NET Framework 4.5, делает.
Вот пример того, как реализовать это доступно здесь.
Вы могли бы использовать ItemsControl
для отображения сообщений об ошибках. Пожалуйста, посмотрите мой ответ здесь для примера.