Styling the Validation Error on WPF DataGridCell
I'm trying to change the way a DataGridCell appears when it has error content. By default, it has a white background and a red border when it encounters an error. However, it seems that my attempts to set the Validation.ErrorTemplate of this class are being ignored, as are my Triggers on the Validation.HasError property. All of the code necessary to reproduce the problem is located below; I have been completely unable to get WPF to apply any kind of stylings to the cell on error. Does anyone see the problem here or have a potential workaround?
APP.XAML
<Application.Resources>
<ControlTemplate x:Key="ErrorTemplate">
<DockPanel>
<TextBlock Text="Busted!"/>
<AdornedElementPlaceholder/>
</DockPanel>
</ControlTemplate>
<Style x:Key="{x:Type WpfToolkit:DataGridCell}" TargetType="{x:Type WpfToolkit:DataGridCell}">
<Style.Setters>
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorTemplate}"/>
<Setter Property="Background" Value="Green"/>
</Style.Setters>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="ToolTip" Value="Doh!"/>
</Trigger>
</Style.Triggers>
</Style>
</Application.Resources>
MainWindow.xaml
<Grid>
<WpfToolkit:DataGrid ItemsSource="{Binding Path=MyItems, ValidatesOnDataErrors=True}" AutoGenerateColumns="False">
<WpfToolkit:DataGrid.Columns>
<WpfToolkit:DataGridTextColumn Header="Wheel Count" Binding="{Binding WheelCount, ValidatesOnDataErrors=True}"/>
<WpfToolkit:DataGridTextColumn Header="Car Colour" Binding="{Binding Color, ValidatesOnDataErrors=True}"/>
</WpfToolkit:DataGrid.Columns>
</WpfToolkit:DataGrid>
</Grid>
The class being bound to is
Car.cs
class Car : IDataErrorInfo, INotifyPropertyChanged
{
public Car(int numWheels, string Color)
{
_color = Color;
_wheelCount = numWheels;
}
private string _color;
public string Color
{
get
{
return _color;
}
set
{
_color = value;
if (value.Length > 10)
{
//Warning
}
if (value.Length > 20)
{
//Error
}
PropChanged("Color");
}
}
private int _wheelCount;
public int WheelCount
{
get
{
return _wheelCount;
}
set
{
_wheelCount = value;
if (value != 4)
{
AddError("WheelCount", "There should be 4 wheels on the car!");
}
else
this.ClearError("WheelCount");
PropChanged("WheelCount");
}
}
public void AddError(string propName, string errorMessage)
{
if (myErrors.ContainsKey(propName))
myErrors.Remove(propName);
myErrors.Add(propName, errorMessage);
PropChanged(propName);
PropChanged("Error");
}
public void ClearError(string propName)
{
if (myErrors.ContainsKey(propName))
myErrors.Remove(propName);
}
private Dictionary<string, string> myErrors = new Dictionary<string, string>();
public string Error
{
get
{
StringBuilder myErr开发者_Python百科or = new StringBuilder("Errors");
foreach (KeyValuePair<string,string> currentErr in myErrors)
{
myError.AppendLine(currentErr.Key + ":" + currentErr.Value);
}
return myError.ToString();
}
}
public string this[string columnName]
{
get
{
if (!myErrors.ContainsKey(columnName))
return null;
else
return myErrors[columnName];
}
}
public void PropChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
The "ViewModel" for the view is CarVM:
CarVM.cs
class CarVM
{
public CarVM()
{
for (int currentCar = 0; currentCar < 20; currentCar++)
{
myCars.Add(new Car(4, "Red"));
}
MyItems = (CollectionView)CollectionViewSource.GetDefaultView(myCars);
}
private List<Car> myCars = new List<Car>();
public CollectionView MyItems
{
get;
private set;
}
}
And the code in the window is very simple:
MainWindow.Xaml.Cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new CarVM();
}
}
DataGrid columns are tricky to style, as the DataContext is not what you expect at the time it is created and the style is applied. See this article, in particular, "Use DataGridColumn.ElementStyle and DataGridColumn.EditingElementStyle to set properties on a cell’s Content."
Instead of AddError
could you please try throw new ArgumentException
like that to confirm?
Does this following condition fails? Not in both wheel count and color
for (int currentCar = 0; currentCar < 20; currentCar++)
{
myCars.Add(new Car(4, "Red"));
}
HTH
That is because there is no error ever generated!! Errors will be added when you assign to Color
& WheelCount
, and not _color
& _wheelCount
. You are never assigning anything to these properties.
Change your constructor to this:
public Car(int numWheels, string color)
{
Color = color;
WheelCount = numWheels;
}
In case, if you don't even see the initial green color than the only reason I can think of is the Build Action of your App.xaml file. Make sure it is ApplicationDefinition
.
精彩评论