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}}"/>
Related
I have both DataGrid and Listbox binded to the same ObservableCollection:
public ObservableCollection<Contact> contacts = new ObservableCollection<Contact>();
CntGrid.ItemsSource = contacts;
CntListBox.ItemsSource = contacts;
<DataGrid x:Name="CntGrid"
IsReadOnly="False"
CanUserAddRows="True"
CanUserDeleteRows="True"/>
<ListBox x:Name="CntListBox"/>
The problem is DataGrid allowing adding items (I want to keep this functionality) causes ListBox to display an empty row aswell. I don't want my ListBox to display this empty row at the end.
Can I somehow modify my ListBox to fix this?
This will hide the {NewItemPlaceholder} item in your ListBox:
<ListBox x:Name="CntListBox">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding}" Value="{x:Static CollectionView.NewItemPlaceholder}">
<Setter Property="UIElement.Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Empty row in DataGrid is a NewItemPlaceholder. It has different type from Contact. So I suggest to use a converter to hide it in ListBox:
public class ObjectTypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var t = parameter as Type;
if (value == null || t == null)
return false;
return t.IsAssignableFrom(value.GetType());
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
use that converter in ListBoxItem Style to check the type of item and hide them if type doesn't match:
<Window.Resources>
<local:ObjectTypeConverter x:Key="tc"/>
</Window.Resources>
<ListBox x:Name="CntListBox">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource tc}, ConverterParameter={x:Type local:Contact}}"
Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
I am following Telerik guide for displaying a tooltip on WPF GridView column headers. The task is to create a tooltip which would have same text as column header.
In generic.xml there is this style:
<Style TargetType="telerik:GridViewHeaderCell">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content}" />
</Style>
This does work and shows a tooltip when mouse is hovered over column header, however the actual header is being cleared.
I wonder why this is happening and how to fix it? GridViewHeaderCell inherits from ContentControl.
I ended up adding a converter because "Content" value appeared to be a TextBlock:
public class TooltipObject : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
return ((TextBlock)value).Text;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
and the style looks like:
<utils:TooltipObject x:Key="tooltip" />
...
<Style TargetType="telerik:GridViewHeaderCell">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content, Mode=TwoWay, Converter={StaticResource tooltip}}" />
</Style>
I am developing a Windows Store (8.1) application.
I have this control which has a nullable int property (type "int?"), when I try to set it to an int via Style, I get an error.
<Setter Property="Minimum" Value="0" />
Error Cannot assign to nullable type on property Minimum
Any ideas?
Following sample depicts solution, adjust it to your demands.
C#:
class IsNullToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value == null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML:
<Window.Resources>
<local:IsNullToBoolConverter x:Key="IsNullToBoolConverter"/>
</Window.Resources>
<TextBlock Text="Text">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Age, Converter={StaticResource IsNullToBoolConverter}}" Value="False">
<Setter Property="FontSize" Value="55"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
you can achieve this by using TargetNullValue property. Use below code,
TargetNullValue={x:Static sys:String.Empty}
Note :
sys is the imported xml namespace for System in mscorlib:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Hope this will help..
I have a ListBox that represents the lines of text in a scripting language. I need to "single-step" the script, highlighting the current script line (say with a green background).
The modelview has a "CurrentLine" property that is the index of the current line so I figured I would write a trigger on the ItemContainerStyle and use a converter to figure out if the index of the list box item is the same as the CurrentLine. But I'm struggling to pass in the current line value to the converter as it comes from the VM, and I can't pass non-constant values into the converter as parameters. Neither can I do so with the "Value" of the trigger. How can I pass these values in?
CURRENTLINE EXPOSED AS REFERENCE TYPE
To modify the ViewModel to save the current line as an actual LineViewModel (or whatever, depending on how your VM exposes the Lines), rather than the selected index is much cleaner solution in my opinion.
Then you can define the trigger using a multibinding with a converter that checks for equality:
<ListBox ItemsSource="{Binding Lines}" x:Name="List">
<ListBox.Resources>
<sample:EqualityConverter x:Key="Converter" />
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="Control">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource Converter}">
<Binding Path="DataContext.CurrentLine" ElementName="List" />
<Binding />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Background" Value="Blue"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
And the converter:
public class EqualityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values[0] == values[1];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
That's it.
CURRENTLINE EXPOSED AS STRING (VALUE TYPE)
If you still want to use an integer index, you can uitilize the AlternationIndex. You set the AlternationCount of the list to the number of its items, which ensures that every item has its unique index and then bind to the attached property ItemsSource.AlternationIndex of the ListBoxItem. This way, you won't mix up lines with the same content.
<ListBox ItemsSource="{Binding Resources}" x:Name="List" AlternationCount="{Binding Resources.Count}">
<ListBox.Resources>
<sample:EqualityConverter x:Key="Converter" />
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource Converter}">
<Binding Path="DataContext.CurrentItem" ElementName="List"/>
<Binding RelativeSource="{RelativeSource Self}" Path="(ItemsControl.AlternationIndex)"/>
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Background" Value="Blue"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
You need to modify the converter slightly:
public class EqualityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return Equals(values[1], values[0] );
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
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;
}