Reputation: 31
I have a bunch of styles that I'm trying to override in order to set an Error Template so that I can display error messages. When using "BasedOn" to attempt to inherit from the style, the base style remains, but the ErrorTemplate displays as a tiny box with no text. If I don't use "BasedOn" it works great, but the base style is no longer present (as expected). Has anyone seen this before?
Styles in question:
<ControlTemplate x:Key="ValidationErrorTemplate">
<StackPanel ClipToBounds="False">
<Border BorderBrush="Red" ClipToBounds="False"
BorderThickness="2" HorizontalAlignment="Left" >
<!-- Placeholder for the DataGridTextColumn itself -->
<AdornedElementPlaceholder x:Name="AdornedElement" />
</Border>
<Border
BorderBrush="Red" ClipToBounds="False"
Padding="1"
BorderThickness="1,1,1,1"
HorizontalAlignment="Left" Background="Black"
Margin="100,0,0,0">
<ItemsControl ItemsSource="{Binding}" HorizontalAlignment="Left">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ErrorContent}" ClipToBounds="False"
Foreground="Red" TextWrapping="WrapWithOverflow" Width="250" Height="100"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
</StackPanel>
</ControlTemplate>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="3"/>
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ValidationErrorTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
Simple Text VM to use:
public class TextValidationVM : INotifyDataErrorInfo, INotifyPropertyChanged
{
private Dictionary<string, List<string>> _Errors;
public TextValidationVM() => this._Errors = new Dictionary<string, List<string>>();
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
protected string _SomeText;
public string SomeText
{
get { return _SomeText; }
set
{
ValidateProperty(value, ValidateText);
SetProperty(ref _SomeText, value);
}
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if (propertyChanged == null)
return;
propertyChanged((object)this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetProperty<T>(
ref T backingStore,
T value,
Action onChanged = null,
[CallerMemberName] string propertyName = "")
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
if (onChanged != null)
onChanged();
this.OnPropertyChanged(propertyName);
return true;
}
private (bool IsValid, IEnumerable<string> ErrorMessages) ValidateText(string arg)
{
return (false, new List<string>() {"This is not valid text"});
}
public IEnumerable GetErrors(string propertyName)
{
List<string> stringList;
return !string.IsNullOrWhiteSpace(propertyName) ? (this._Errors.TryGetValue(propertyName, out stringList) ? (IEnumerable)stringList : (IEnumerable)new List<string>()) : (IEnumerable)this._Errors.SelectMany<KeyValuePair<string, List<string>>, string>((Func<KeyValuePair<string, List<string>>, IEnumerable<string>>)(entry => (IEnumerable<string>)entry.Value));
}
public bool HasErrors => this._Errors.Any<KeyValuePair<string, List<string>>>();
public bool ValidateProperty<TValue>(
TValue value,
Func<TValue, (bool IsValid, IEnumerable<string> ErrorMessages)> validationDelegate,
Action onInvalid = null,
Action onValid = null,
[CallerMemberName] string propertyName = "")
{
this._Errors.Remove(propertyName);
this.OnErrorsChanged(propertyName);
(bool, IEnumerable<string>) valueTuple = validationDelegate(value);
if (!valueTuple.Item1)
{
foreach (string errorMessage in valueTuple.Item2)
this.AddError(propertyName, errorMessage);
if (onInvalid != null)
onInvalid();
}
else if (onValid != null)
onValid();
return valueTuple.Item1;
}
public void AddError(string propertyName, string errorMessage, bool isWarning = false)
{
List<string> stringList;
if (!this._Errors.TryGetValue(propertyName, out stringList))
{
stringList = new List<string>();
this._Errors[propertyName] = stringList;
}
if (stringList.Contains(errorMessage))
return;
if (isWarning)
stringList.Add(errorMessage);
else
stringList.Insert(0, errorMessage);
this.OnErrorsChanged(propertyName);
}
public bool PropertyHasErrors(string propertyName)
{
List<string> source;
return this._Errors.TryGetValue(propertyName, out source) && source.Any<string>();
}
protected virtual void OnErrorsChanged(string propertyName)
{
EventHandler<DataErrorsChangedEventArgs> errorsChanged = this.ErrorsChanged;
if (errorsChanged == null)
return;
errorsChanged((object)this, new DataErrorsChangedEventArgs(propertyName));
}
}
WPF Window Content:
<Grid>
<TextBox Text="{Binding SomeText}" MaxHeight="100"/>
</Grid>
Code behind:
public MainWindow()
{
InitializeComponent();
DataContext = new TextValidationVM() {SomeText = "This is text"};
}
With all of the above implemented it should always spit out an error below the TextBox that says: "This is not valid text"
Upvotes: 0
Views: 37