This is my GridViewColumn
:
<GridViewColumn Width="180" Header="Status">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Txt" Text="{Binding Status}" Foreground="Yellow" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
The Status field
is a property of my binding object and all i want to do is change this GridViewColumn
color but this time base on condition:
I have another propgerty called StatusMessage
which is simple enum
:
public enum StatusMessage
{
InProcess,
Done,
Wait
}
So this enum
property is changing all the time and for every value of this enum
i want to define different color.
Is it possible ?
Edit
My View model class inherit from BaseObservableObject
:
public class BaseObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
{
var propName = ((MemberExpression)raiser.Body).Member.Name;
OnPropertyChanged(propName);
}
protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(name);
return true;
}
return false;
}
}
My properties:
public string Status
{
get { return _status; }
set
{
_status = value;
OnPropertyChanged();
}
}
public StatusMsg StatusMessage
{
get { return _statusMsg; }
set {
_statusMsg = value;
OnPropertyChanged();
}
}
XAML:
<GridViewColumn Width="180" Header="Status" DisplayMemberBinding="{Binding Status}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Foreground="{Binding StatusMsg,Converter={c:StatusMessageToColorConverter}}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
StatusMessageToColorConverter
is the same as @grek40 suggested and still my TextBlock
Foreground
not changing.
I first focus on the value conversion, then I say something about the other requirement ("So this enum property is changing all the time and for every value of this enum i want to define different color.")
Since you have an enum value but you want to have a color specification, you need to convert the value. This can be done with the help of an implementation of the IConverter
interface. There are different ways to reference a converter in XAML, I additionally inherit from MarkupExtension
so I am able to access the converter directly.
public class StatusMessageToColorConverter : MarkupExtension, IValueConverter
{
// one way converter from enum StatusMessage to color
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is StatusMessage && targetType == typeof(Brush))
{
switch ((StatusMessage)value)
{
case StatusMessage.InProcess:
return Brushes.Yellow;
case StatusMessage.Done:
return Brushes.Green;
case StatusMessage.Wait:
return Brushes.Red;
}
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public StatusMessageToColorConverter()
{
}
// MarkupExtension implementation
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
As you can see, I convert if the input value is of type StatusMessage
and the target type is typeof(Brush)
, which is the Type of the Foreground
property. I just chose some colors, you may use different colors or even more complex brushes if you like.
In XAML, the namespace of the converter needs to be referenced. In my case its just WpfApplication2
associated to the XAML namespace name c
<Window
[... other properties]
xmlns:c="clr-namespace:WpfApplication2">
Now, when binding to the foreground property, utilize the converter
<TextBlock Text="{Binding Status}" Foreground="{Binding StatusMessage,Converter={c:StatusMessageToColorConverter}}" />
This should do the trick.
Now to the other part about dynamically changing the value. Your viewmodel class needs to implement INotifyPropertyChanged
and raise the PropertyChanged
event whenever a value is changed. As an example, see the following class that only contains the two properties of your example and the necessary notification logic.
public class ItemModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
void NotifyPropertyChanged([CallerMemberName]string prop = null)
{
var tmp = PropertyChanged;
if (tmp != null) tmp(this, new PropertyChangedEventArgs(prop));
}
private string _Status;
public string Status
{
get { return _Status; }
set { _Status = value; NotifyPropertyChanged(); }
}
private StatusMessage _StatusMessage;
public StatusMessage StatusMessage
{
get { return _StatusMessage; }
set { _StatusMessage = value; NotifyPropertyChanged(); }
}
}
More complex viewmodels can follow the same approach. For less update overhead, compare the current value and the new value in the setter and only notify if the value actually changes.