DataTriggerBehavior is not working for null values - c#

I am trying to set visibility of my stackpanel to collapsed if value is null, but DataTriggerBehavior is not changing it's visibility value, If I change value to something else than it work's, below is the xaml for that:
<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{Binding Name}"
Value="{x:Null}">
<Core:ChangePropertyAction TargetObject="{Binding ElementName=spName}"
PropertyName="Visibility"
Value="Collapsed" />
</Core:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>

One option is to use a simple converter which presumes Name is a String and returns an empty String if value is null else returns the value as a String
public class NullToEmptyStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
return "";
else
return value.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
And your xaml will reference NullToEmptyStringConverter NB local is the namespace where I've created the converter class it maybe different in your app
<Page.Resources>
<local:NullToEmptyStringConverter x:Key="NullToEmptyStringConverter"/>
</Page.Resources>
and your DataTrigger
<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{Binding Name, Converter={StaticResource NullToEmptyStringConverter}}"
Value="">
<Core:ChangePropertyAction TargetObject="{Binding ElementName=spName}"
PropertyName="Visibility"
Value="Collapsed" />
</Core:DataTriggerBehavior>

Related

Converter to Bool

I have a normal Checkbox, where I want to set the IsChecked property to a Binding resource.
The resource is a self written class myClass, which can be null or referenced (means not null).
The Checkbox should be NOT checked, if the assigned object myObject (out of myClass) is null
and checked, if it is not null.
What do I have to write in the IsChecked="..." property in my xaml file?
You can create a style with a DataTrigger that sets the IsChecked property.
<CheckBox>
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="IsChecked" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding MyObject}" Value="{x:Null}">
<Setter Property="IsChecked" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
An alternative is to create a reusable value converter.
public class NotNullToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException();
}
}
Create an instance of the converter in any resource dictionary, e.g. application resources.
<local:NotNullToBooleanConverter x:Key="NotNullToBooleanConverter"/>
This converter can be used directly in the binding.
<CheckBox IsChecked="{Binding MyObject, Converter={StaticResource NotNullToBooleanConverter}}"/>

Replacing delete button with restore depending on boolean value in WPF

I have boolean column named "deleted" in mysql.
1)if the row is not deleted it shows the delete button.
2)if the row is deleted it should display retore button in that datagrid cell instead of deleted with the query of restore behind it.
right now i can only disable the button if the row is deleted.
My code is as follows.
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Delete" Name="btnDelete"
Click="btnDelete_Click">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding deleted}" Value="False">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
The main idea is using converter that will convert bool value to visibility.
However, for restore button, you will need to invert the visibility behavior, therefore custom converter comes in mind
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is bool boolValue))
throw new InvalidOperationException();
if (parameter == null || (parameter is bool invertVisibility && !invertVisibility))
return boolValue ? Visibility.Visible : Visibility.Collapsed;
else
return boolValue ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then your buttons will use the same converter registered as:
<Window.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"></local:BoolToVisibilityConverter>
</Window.Resources>
But one of them will pass additional parameter so that converter will invert its logic:
<Button Margin="5" Content="Delete"
Visibility="{Binding deleted, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=true}"
Command="{Binding DeleteCommand}"></Button>
<Button Margin="5" Content="Restore"
Visibility="{Binding deleted, Converter={StaticResource BoolToVisibilityConverter}}"
Command="{Binding RestoreCommand}"></Button>
You can use the built-in BoolToVisibilityConverter and set the Visibility Property, you might not need a trigger for this
...
<Window.Resources>
<BooleanToVisibilityConverter x:Key="VisibleIfTrueConverter" />
</Window.Resources>
...
<Button Visibility={Binding deleted, Converter={StaticResource VisibleIfTrueConverter}}/>

Check in Data Trigger if object is particular class

Is there a way to check in DataTrigger if the object is of a particular class?
In fact I would like that DataTrigger answer this question in C#:
if(MyObject is MyClass)
I want it to look something like this in XAML:
<Grid>
<Grid.Triggers>
<DataTrigger Binding="{Binding MyObject}" Value="MyClass?">
<Setter..../>
</DataTrigger>
</Grid.Triggers>
</Grid>
You can use a converter for this:
<Grid>
<Grid.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding MyString, Converter={StaticResource OConv}, ConverterParameter=System.String}" Value="True">
<Setter Property="Grid.Background" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>
Use the ConverterParameter to state the type of the object you expect to receive...
Converter will return true if it matches or false otherwise...
Example of converter:
public clas s ObjectTypeToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.GetType().ToString() == (string)parameter)
{
return true;
}
return false;
}

DataTrigger Comapring Date Values to set Cell Style

I am creating a Fault Log Application, bound to a database
The primary use of what I want is to format the DateTime cell to RED if the DateTime
listed is greater than 3 weeks prior to the current date.
MainWindow.xaml
<DataGrid AutoGenerateColumns="False" Height="379" HorizontalAlignment="Left" Margin="0,36,0,0" Name="dataGridLog" VerticalAlignment="Top" Width="432" SelectionChanged="dataGridLog_SelectionChanged" IsReadOnly="True" MouseDoubleClick="dataGridLog_MouseDoubleClick" ItemsSource="{Binding}" RowDetailsVisibilityMode="VisibleWhenSelected">
<DataGrid.Columns>
<DataGridTemplateColumn x:Name="dateColumn" Header="Date" Width="80" CanUserReorder="True" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="dateColumnTextBlock" Text="{Binding Path=DateSent, StringFormat={}{0:dd/MM/yyyy}}" Width="80" />
<DataTemplate.Triggers>
<!--<DataTrigger Binding="{Binding Path=DateSent, StringFormat={}{0:dd/MM/yyyy}, Converter={x:Reference mIsEqualOrGreaterThanConverter.Instance}, ConverterParameter=3}" Value="True">
<Setter TargetName="dateColumnTextBlock" Property="Background" Value="Red" />
</DataTrigger>-->
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn x:Name="priorityColumn" Header="Priority" Width="80" CanUserReorder="True" CanUserSort="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="priorityColumnTextBlock" Text="{Binding Path=Priority}" Width="80" />
<!--<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Priority}" Value="Urgent">
<Setter TargetName="priorityColumnTextBlock" Property="Background" Value="Red" />
</DataTrigger>
</DataTemplate.Triggers>-->
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn x:Name="titleColumn" Binding="{Binding Path=Fault}" Header="Title" Width="270" CanUserReorder="True" CanUserSort="True" />
</DataGrid.Columns>
</DataGrid>
MainWindow.xaml.cs
[ValueConversion(typeof(DateTime), typeof(String))]
public class DateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DateTime date = (DateTime)value;
DateTime curDate = DateTime.Now;
TimeSpan span = curDate.Subtract(date);
return span.Days;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
string strValue = value as string;
DateTime resultDateTime;
if (DateTime.TryParse(strValue, out resultDateTime))
{
return resultDateTime;
}
return DependencyProperty.UnsetValue;
}
}
I cannot seem to bind the converter, not able to convert the dates.
If you have declared your Converter in Resources
<Window.Resources>
<local:IsEqualOrGreaterThanConverter x:Key="IsEqualOrGreaterThanConverter" />
</Window.Resources>
you can reference it like this
<DataTrigger Binding="{Binding Path=DateSent, Converter={StaticResource IsEqualOrGreaterThanConverter}, ConverterParameter=3}" Value="True">
<Setter TargetName="dateColumnTextBlock" Property="Background" Value="Red" />
</DataTrigger>
Your DataTrigger compares with True. Therefore your Converter should return a bool.
[ValueConversion(typeof(DateTime), typeof(bool))]
public class IsEqualOrGreaterThanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DateTime date = (DateTime)value;
DateTime curDate = DateTime.Now;
TimeSpan span = curDate.Subtract(date);
return span.TotalDays > (int)parameter * 7;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

XAML with MultiDataTrigger and NullToBoolConverter

I try to get a Button to Enable if all textbox have a value but it doesn´t work and i can´t find out why.
NullToBoolConverter.cs
public class NullToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(bool));
bool nullResult = false;
if (parameter != null)
nullResult = (bool)converter.ConvertFrom(parameter);
if (value == null)
return nullResult;
else
return !nullResult;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
XAML-Ressourcedict.
<ex:NullToBoolConverter x:Key="NullToBoolConverter"/>
<Style x:Key="okButtonStyle" TargetType="{x:Type Button}">
<Setter Property="IsEnabled" Value="False" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Hostadress, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}" Value="True" />
<Condition Binding="{Binding UserBox, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}" Value="True" />
<Condition Binding="{Binding PasswordTextBox, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}" Value="True" />
<Condition Binding="{Binding PortBox, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="True" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
I changed your converter to this, as it just seemed to be a lot simpler...
public class NullToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return false;
string currentValue = value.ToString();
if (string.IsNullOrWhiteSpace(currentValue))
return false;
return true;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
Then your XAML style should look like this...
<ex:NullToBoolConverter
x:Key="NullToBoolConverter" />
<Style
x:Key="okButtonStyle"
TargetType="{x:Type Button}">
<Setter
Property="IsEnabled"
Value="False" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition
Binding="{Binding ElementName=Hostadress, Path=Text, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}"
Value="True" />
<Condition
Binding="{Binding ElementName=UserBox, Path=Text, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}"
Value="True" />
<Condition
Binding="{Binding ElementName=PasswordTextBox, Path=Text, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}"
Value="True" />
<Condition
Binding="{Binding ElementName=PortBox, Path=Text, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}"
Value="True" />
</MultiDataTrigger.Conditions>
<Setter
Property="IsEnabled"
Value="True" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
Debugging worked and typing in all of the textboxes would enable the button.
Notice that I changed the Binding statements to use the ElementName and Path.
I simplified a little bit code:
[ValueConversion(typeof(object), typeof(bool))]
public class NullToBoolValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var result = value == null;
return parameter != null ? !result : result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
I tried your code and I your only problem is that you are only comparing the value to null and not to string.Empty. Try this
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(bool));
bool nullResult = false;
if (parameter != null)
nullResult = (bool)converter.ConvertFrom(parameter);
if (value == null || value.ToString() == string.Empty)
return nullResult;
else
return !nullResult;
}

Categories

Resources