I have a combobox which is bound to an Enum datatype. Right now the combobox binding works fine but when I tried to bind the visibility of a checkbox to the combobox selection, this binding is not working as expected. What I wanted to do was whenever the combobox selection is "Restore", I want a checkbox to be visible. Below is the code that I am using.
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=cmbOperation, Path=SelectedValue}" Value="Restore">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
I tried changing the Path between SelectedValue, SelectedItem , SelectedValue.TosString() (hopelessly) but I am not getting the checkbox to change its visibility whenever the combobox has "Restore" as its selection. Should I be making any changes in the Enum that I am binding to the Combobox ? If not, what else am I doing wrong?
I'm willing to bet that you've set Visibility on the CheckBox in the XAML:
<CheckBox
Visibility="Collapsed"
>
However, due to the rules of Dependency Property Value Precedence in WPF, that will override anything that happens in the Style. This is by design and it's not a bad idea when you think through all the implications, but it bites everybody who's new to WPF.
It's an easy fix: Just set the starting value in a Setter in the Style. What the Style does, the Style can undo.
<CheckBox
>
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=cmbOperation, Path=SelectedValue}" Value="Restore">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
Related
I am creating a WPF DataGrid control with a DataGridTemplateColumn CheckBox which should have the IsChecked property set as true or false depending on a DataTable value)...
If the DataTable row has the value set as 1, the DataGridTemplateColumn should be true (checked). Otherwise, it will be false (unchecked)... by default, every new row will be set as true, but I couldn't bind these CheckBox rows to my DataTable value (which will be 1 or 2)
I tried the following c# code. It works when I finish the UserControl edition and loop through my DataTable to save its values... But, when I set gridResultados.ItemsSource = dataTable.DefaultView clearly not checking/unchecking my CheckBoxes because there is no binding between the DataTable column value (1 or 2) and my DataGridTemplateColumn ... this is my closest approach:
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Value?" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="True" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked">
<Style TargetType="{x:Type CheckBox}">
<Style.Triggers>
<Trigger Property="Content" Value="1">
<Setter Property="IsChecked" Value="True"/>
</Trigger>
<Trigger Property="Content" Value="2">
<Setter Property="IsChecked" Value="False"/>
</Trigger>
</Style.Triggers>
</Style>
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
dataTable.Rows[gridResultados.SelectedIndex].SetField(4, 1);
}
private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
{
dataTable.Rows[gridResultados.SelectedIndex].SetField(4, 2);
}
Firstly I recommend you not to use DataTable in WPF, because we usually use EF in WPF, the DataTable is part of ADO.NET and it's old and nearly deprecated.
For your problems, you have somethings to fix involving the Binding and the Trigger. First the implicit DataContext in each row here is a DataRowView. It's available only for DataTrigger to use (not for Trigger). So you need to use DataTrigger instead to listen to the index [4] (which references to the fifth column - the column of CheckBox). Second the Style you set is wrong, it should be wrapped in CheckBox.Style to make it understand that you set Style for CheckBox, not for its Content. Third the Style Trigger cannot override locally set IsChecked (as in your code), in this case the template Trigger can override that, but you can also use a Style Setter to set default value True for IsChecked.
Here is the code you should have:
<DataGridTemplateColumn Header="Value?">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked">
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="IsChecked" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding [4]}" Value="1">
<Setter Property="IsChecked" Value="True"/>
</DataTrigger>
<DataTrigger Binding="{Binding [4]}" Value="2">
<Setter Property="IsChecked" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
<CheckBox.Style>
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
BTW, I can see that you use event handler to update the value of the underlying data. But that's not the right way to go in term of MVVM where almost what you need is Binding and related stuff. However that part is yours, you need to research more on that. I think it's enough to end this problem here.
I want to have a StackPanel who's visibility should be depending on a Combobox selection. Unfortunatly the XAML below does not work.
I found a solution with a new property which will be set on the PropertyChanged event of the Combobox selection, though I would prefer a strict XAML solution for this.
Any hints on how to solve this?
<StackPanel>
<Label>Picture in Picture function</Label>
<ComboBox Name="cbPictureInPicture" ItemsSource="{Binding Path=PictureInPictureCodeList, Mode=OneWay}" DisplayMemberPath="CodeText"
SelectedValuePath="CodeID" SelectedValue="{Binding Path=PictureInPicture, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
<StackPanel>
<StackPanel.Style>
<Style TargetType="StackPanel">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=cbPictureInPicture, Path=IsSelected.CodeText}" Value="Yes">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<Label>Picture in Picture is used</Label>
(...)
</StackPanel>
you may perhaps rewrite the same as
<DataTrigger Binding="{Binding ElementName=cbPictureInPicture, Path=SelectedItem.CodeText}" Value="Yes">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
assuming the combobox is bound to a collection whose item has CodeText property. so SelectedItem.CodeText will point to the same.
additionally it may not be required to set <Setter Property="Visibility" Value="Visible" /> as it is the default value. it does not have any effect in this case just some extra line of code which can be removed.
You can also use a converter and bind directly to the PictureInPicture property:
<StackPanel Visibility="{Binding PictureInPicture, Converter={StaticResource myVisibilityConverter}}"/>
<Label>Picture in Picture is used</Label>
(...)
</StackPanel>
Create flags and pass this flag in stackpanel visibility converter.
On the basis of flag in converter make decision stackpanel visible/hide whatever
Set this flat in comboBox selection change event if selected value as per your requirement.
I would like to make a WPF usercontrol that shows a string when and only when the datacontext == null. I'm using the TargetNullValue attribute in binding to display a custom string when the datacontext is null, and that's working as intended. But when the datacontext is non-null, it just shows the ToString value, which I would like to get rid of.
Of course I could solve this easily by using a valueconverter, but I'd like to find a way to solve this with xaml only. Does anyone know a way to do it?
In case you want TextBlock to be shown only in case binding value is null, you can have trigger in place and set Visibility to Visible when binding value is null and otherwise Collapsed always.
<TextBlock Text="{Binding TargetNullValue=NullValue}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding}" Value="{x:Null}">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Use a data trigger on {x:Null}. There are many options using styles, data templates etc., depending on taste and needs. For instance:
<DataTemplate x:Key="ShowOnNull">
<TextBlock x:Name="text"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}" Value="{x:Null}">
<Setter TargetName="text" Property="Text" Value="your custom string"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
...
<ContentPresenter ContentTemplate="{StaticResource ShowOnNull}"
Content="{Binding ...}"/>
How do I achieve the following:
<ComboBox
IsEnabled="{Binding bVisibilty = AnotherCollection.Count > 0 ? true:false}"/>
I can use a converter which will be converting count to boolen, but is there a better way of doing than overdoing converter everywhere.
You can use style triggers for that like so :
<ComboBox >
<ComboBox.Style>
<Style TargetType="ComboBox">
<Style.Triggers>
<DataTrigger Binding="{Binding AnotherCollection.Count}" Value="0">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
Obviously AnotherCollection needs to be an ObservableCollection so the UI will be notified every time item is being added\removed to it
You could bind to a Property on your ViewModel and put the boolean and INPC logic in the viewmodel
I'm trying to apply a DataTrigger to a Button and it depends on a property from the currently selected item of a TreeView. The idea is that I want to change the text of a Button depending on a property of the selected item.
What I have looks like this:
<Button x:Name="m_AddObject" Margin="192.708,0.909,6,6.363" Click="AddObject_Click" >
<DataTrigger Binding="{Binding ElementName=ObjectTreeView, Path=SelectedItem.Removable}" Value="true">
<Setter TargetName="m_AddObject" Property="Content" Value="Remove" />
</DataTrigger>
</Button>
But I can't get it to compile. The Setter complains about "Content" not being valid because it doesn't have a qualifying type name, but if I change it to "Button.Content" it then complains of "Object reference not set to an instance of an object".
I also tried:
<Setter TargetName="m_AddObject.Content" Value="Remove" />
While that compiles, it didn't work either.
I'm stumped.
Any ideas?
Thanks!
DataTriggers should be defined in a Style for the button. What you're trying to do above is essentially use a DataTriggers as the "label" (the "Content", as WPF puts it) for the button (instead of, say, "OK").
This is ad-hoc, so it might not be totally correct, but it's closer to what you want:
<Button x:Name="m_AddObject"
Margin="192.708,0.909,6,6.363"
Click="AddObject_Click">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ObjectTreeView, Path=SelectedItem.Removable}" Value="True">
<Setter Property="Content" Value="Remove" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>