I need to do a component where checkboxes change into radiobuttons when certain property changes. I have no idea how to do that kind of change in xaml. The checkbox is in a datatemplate as shown below. Now I just need some kind of logic to change it into a radiobutton.
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected.Value, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</DataTemplate>
Especially when there are a lot of instances, the solution of having both controls within the DataTemplate and changing visibility might not be ideal considering performance and memory usage. In this case, a DataTemplateSelector might do the trick - see this tutorial
you can put both CheckBox and RadioButton in one container (StackPanel for example) in DataTemplate and just collapse one of them according to your condition using DataTrigger.
i hope it'll help you. sorry for my pure english.
<DataTemplate>
<StackPanel>
<CheckBox Content="CheckBoxHeader">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Condition}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
<RadioButton Content="RadioButtonHeader">
<RadioButton.Style>
<Style TargetType="RadioButton">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Condition}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
</RadioButton>
</StackPanel>
</DataTemplate>
Related
I have a C# wpf mvvm application and some data is coming from db. I have a combobox and what I want to achieve is: when the data from db is not in the combobox list, in the combobox I want to be writen:"Not found data". If it is possible I want to do this from the xaml.
I have tried :
<Trigger Property="SelectedItem" Value="{x:Null}">
<Setter Property="Text" Value="No Item Selected"/>
</Trigger>
but it is not working.
the easiest i can think of is to overlay a textblock
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="100">
<ComboBox x:Name="myComboBox" ItemsSource={Binding ...}"/>
</ComboBox>
<TextBlock Text="No data found" IsHitTestVisible="False" Margin="3">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItem, ElementName=myComboBox}" Value="{x:Null}">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
Control libraries like telerik or devexpress often contain controls with this feature.
I use Visual Studio 2019 with WPF / MVVM.
I have set a trigger to a textbox to control its visibiliy.
And during runtime this works well, the trigger checks the state of a radiobutton and sets the visibiliy of the textbox accoring to the radiobutton's state.
But during designtime this textbox is not visible.
How could I make this textbox to be visible during designtime ?
This is the XAML I have for the trigger:
<Style x:Key="text" TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Radiobutton1, Path=IsChecked}" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=Radiobutton1, Path=IsChecked}" Value="false">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
<TextBox Style="{StaticResource text}" Text="test..... />
I found this article https://social.msdn.microsoft.com/Forums/en-US/cacc5c30-8aa0-43c5-ad07-b063028653a2/designmode-and-visibility?forum=wpf and did some tests using "DesignerProperties.IsInDesignMode" but I can not make this run,I get errors like "datatrigger can not be added to setterbasecollection".
Also I don't know if "DesignerProperties.IsInDesignMode" is the right approach...
I think the answer is even simpler. By adding d:Visibility="Visible", the textbox will be visible at design time.
<TextBox d:Visibility="Visible" Style="{StaticResource text}" Text="test..... />
This is a workaround:
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Radiobutton1, Path=IsChecked}" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=Radiobutton1, Path=IsChecked}" Value="false">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding Designtime}" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
then in Viewmodel:
public bool Designtime { get; set; }
public ViewModel()
{
if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
{
Designtime = true;
}
}
And in the Window Tag
d:DataContext="{d:DesignInstance {x:Type local:ViewModel},IsDesignTimeCreatable=True}"
You can use the Blend namespace IsHidden attribute:
add the Blend namespace if missing: xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
add the d:IsHidden="True" attribute on the element you want to hide at design time
Example:
<TextBox Style="{StaticResource text}" Text="test....." d:IsHidden="True"/>
I have a DataGrid with data binding to DataTable with columns set to auto generate.
The first column has boolean data type replaced with DataGridTemplateColumn with CheckBox from DataTemplate. It all works fine as it is.
However, now I want to make the DataGridCell background to red when the CheckBox is not checked.
The problem is, I have no idea how to set CheckBox's parent DataGridCell style with IsChecked trigger.
WPF:
<Window.Resources>
<DataGridTemplateColumn x:Key="colSelect">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="chkBxSelect"
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsChecked="{Binding Path=Select, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Click="chkBxSelect_Click">
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<CheckBox x:Name="chkBxSelectAll"
Content="Select"
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsThreeState="True"
Click="chkBxSelectAll_Click"
IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.SelectAll}">
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Foreground" Value="White"></Setter>
<Setter Property="Background" Value="DarkGray"></Setter>
<Setter Property="BorderBrush" Value="Red"></Setter>
<Setter Property="BorderThickness" Value="1"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
</Window.Resources>
C# while DataGrid Column AutoGenerating:
DataGridTemplateColumn col = (DataGridTemplateColumn)Resources["colSelect"];
e.Column = col;
e.Column.IsReadOnly = false;
Update:
So far I have figured out it could be done using RelativeSource and AncestorType in Binding. However, still trying to make it work.
Well after struggling a lot and not even trying the most obvious solution. I found it. It was relatively very simple and easy.
Just added DataTrigger to DataGridCell style and all done, WPF is magic.
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Foreground" Value="White"></Setter>
<Setter Property="Background" Value="DarkGray"></Setter>
<Setter Property="BorderBrush" Value="Red"></Setter>
<Setter Property="BorderThickness" Value="1"></Setter>
</Trigger>
<DataTrigger Binding="{Binding Path=Select, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="False">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
It is a very common thing people do and I understand how it works. I just can't find a way to make it work by only the use of a Style.
Lets say I have this ItemsControl:
<ItemsControl ItemsSource="{Binding stuffList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid ... />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If I wanted to add an alternating row color I would do something like this:
<ItemsControl ItemsSource="{Binding stuffList}" AlternationCount="2">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid x:Name="InnerGrid" ... />
<DataTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="Blue" TargetName="InnerGrid"/>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="Red" TargetName="InnerGrid"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
But I want to clear the xaml from this unwanted additionnal code. I will also need to re-use this mechanic. What do I do? I make a Style!
So, I want to apply a style to the ItemsControl like this:
<ItemsControl ItemsSource="{Binding stuffList}" Style="{StaticResource AlternateStyle}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid ... />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
and let the magic happen in a stylesheep somewhere else like that:
<Style TargetType="ItemsControl" x:Key="AlternateStyle">
<Setter Property="AlternationCount" Value="2"/>
<Style.Resources>
<Style TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}" Value="0">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}" Value="1">
<Setter Property="Background" Value="Blue"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
But it doesn't work.. I'm not able to find the correct Binding or TargetType for the Style (that would replace Grid here). I'm out of idea and can't find help where this is not handled in the xaml. I could use some help from experienced WPF programmers.
Thanks in advance.
I have the following question : what do I need to add in the code below to tell my RadioButton to bind on "IsFacturation" boolean that is attached to datagrid item ? I use a DataTrigger which defines its own binding onto datagrid readonly state, so I need to "get back" in binding definition, probably by looking at appropriate parent. I think I have to play with RelativeSource...
I observe that when a datagrid item has IsFacturation boolean set to true, the radio button isn't checked as it should be.
DataGrid items are an observable collection of "Adresse" objects, which define an "IsFacturation" property.
<DataGrid x:Name="AddressGrid" SelectionUnit="Cell" ItemsSource="{Binding Path=Adresses}" SelectionMode="Single">
<DataGrid.Columns>
<!-- Region Facturation -->
<DataGridTemplateColumn Header="Facturation" SortMemberPath="IsFacturation" HeaderStyle="{StaticResource CenterAlignmentColumnHeaderStyle}" >
<DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<ContentControl>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=AddressGrid,Path=IsReadOnly}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<!-- Possibly create another contentcontrol which differentiates between errors -->
<DataTemplate>
<Image Source="Resources/Images/Check-icon.png" Visibility="Visible"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=AddressGrid,Path=IsReadOnly}" Value="False">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<RadioButton GroupName="grpRadioButtonFacturationAddresses"
IsChecked="{Binding Path=IsFacturation, UpdateSourceTrigger=LostFocus, Mode=TwoWay}" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="Visible"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The goal of such code is to display an image when datagrid is readonly, and a radio button when it's not. I still have to work on image visibility (easy), but radio button state is directly linked to datagrid item property of my choice.
Thanks a lot
This is just answering your comment, not your question. One way that you could use DataTriggers without a ContentControl is to move them to the actual controls:
<DataTemplate>
<Grid>
<Image Source="Resources/Images/Check-icon.png" Visibility="Visible">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Visibility="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=AddressGrid,Path=IsReadOnly}" Value="True">
<Setter Property="Visibility" Value="Visible">
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<RadioButton GroupName="grpRadioButtonFacturationAddresses" IsChecked="{Binding Path=IsFacturation, UpdateSourceTrigger=LostFocus, Mode=TwoWay}" VerticalAlignment="Center" HorizontalAlignment="Center">
<RadioButton.Style>
<Style TargetType="{x:Type RadioButton}">
<Setter Visibility="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=AddressGrid,Path=IsReadOnly}" Value="True">
<Setter Property="Visibility" Value="Collapsed">
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
</RadioButton>
</Grid>
</DataTemplate>
I think I found the cause of our problem.
I suppress the ContentControl and the binding of my radiobutton working now.
Edit: Oh, I had not seen your response Sheridan :)