DataTrigger does not work as expected - wpf

I have a ComboBox bound to a ViewModel property called Property.
Property is a TypeDescriptor.
When user changes the value in the ComboBox, the Property is updated.
On the UI i would like to either hide or make visible different controls: textbox, combobox, date picker etc.
Problem is, the DataTrigger is not working as expected.
<Style x:Key="textboxStyle"
TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Property.PropertyType}"
Value="{x:Type Type={x:Type sys:String}}">
<Setter Property="Visibility"
Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>

You might need to write a Converter which gets invoked when the value of 'Property' changes. The converter can be a 'TypeDescriptior to Visibility converter.
The reason why the above doesnt work is because 'PropertyType' doesnt trigger INotifyPropertyChanged.

Related

WPF: Master/Detail - Disable detail TextBoxes if no records?

I have an ObservableCollection of custom objects bound via a DataContext to a ListBox.
Next to the ListBox a have a group of TextBox that are bound to the current item's field. (i.e. Text={Binding Path=/SomeField})
How can I disable / grey out the record detail TextBoxes when my DataContext's ObservableCollection is empty?
You could do it with a style:
<Style TargetType="TextBox">
<Style.Triggers>
<!-- When the collection itself is null -->
<DataTrigger Binding="{Binding }" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
<!-- When the collection has no items -->
<DataTrigger Binding="{Binding Count}" Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
This answer assumes that you are using mvvm and have a viewmodel to back up your view - I would create a readonly bool property in your viewmodel and return true if the count of your observable collection > 0.
You can then bind the bool to the isEnabled property of the necessary text boxes, thus enabling or disabling them depending upon the value(s) of your observable collection.
EDIT - As per BenjaminPaul's comment below, the change event must be handled for your observable collection and you should then call propertyChanged on your bool property to ensure is is updated and passed back to the view.

wpf datatrigger + value binding

I have a custom component that should change your alignment as a property of the window changes and getting the value of another property of itself. The property of the window is changing correctly, however, the alignment of the component is not changing. The converter that returns the alignment is also working correctly (it returns Left, Right or Center, depending on the other property of the component). So where is the error? Here is the code of the DataTrigger:
<myComponent.Resources>
<lib:HorizontalAlignmentConverter x:Key="HorizontalAlignmentConverter"/>
<Style TargetType="{x:Type myComponent}" x:Key="HorizontalAligner">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MainWindow1, Path=myWindowResizedProperty}" Value="True">
<Setter Property="HorizontalAlignment" Value="{Binding Path=myOtherProperty, RelativeSource={RelativeSource Self}, Converter={StaticResource HorizontalAlignmentConverter}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</myComponent.Resources>
Thanks in advance!
Another question: Is there any way I can reference, in the expression of DataTrigger Binding, the Window object, without using his name? This way would be more generic.
Thanks again!

How Biniding Mode(TwoWay) works?

I was trying out some dummy application just to test binding modes. So, just curious to know how did the binding modes work. I have this xaml code-
<Button x:Name="btn"
Height="20"
Width="200"
VerticalAlignment="Top">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="IsEnabled"
Value="{Binding CanEnable, Mode=TwoWay}" />
<Style.Triggers>
<DataTrigger Binding="{Binding TextChanged}" Value="true">
<Setter Property="IsEnabled"
Value="true" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Here by button IsEanbled is binded to my viemodel property "CanEanble" whose default value is false. Now in my trigger i was listening to "TextChanged" property and setting button IsEnabled to true. Button gets enabled as it should be but the property "CanEnable" did not set to true even the biding mode is set to TwoWay..
Why this is happening??
By setting the value in the trigger you basically remove the binding you previously set in the style setter. Take a closer look at the style. You will notice that you basically you set the property IsEnabled twice. First in the style setter, second in the trigger. It is logical that the second value overrides the previous value.
The desired effect can be achieved from code if you set the value of the dependency property using SetCurrentValue method:
SetCurrentValue(Button.IsEnabledProperty, true);
This way the bindings set on this property will not be removed and it will work as expected.

WPF ComboBox - showing something different when no items are bound

I have a ComboBox, and i want to change its look when the ItemsSource property is null. When it is in that state, i want to show a TextPanel with the text "Retrieving data" in it, and give it a look kind of similar to the watermarked textbox.
I figure to do this i need a ControlTemplate, and a trigger. I have the ControlTemplate here:
<ControlTemplate x:Key="LoadingComboTemplate" TargetType="{x:Type ComboBox}">
<Grid>
<TextBlock x:Name="textBlock" Opacity="0.345" Text="Retrieving data..." Visibility="Hidden" />
</Grid>
<!--
<ControlTemplate.Triggers>
<Trigger Property="ComboBox.ItemsSource" Value="0">
<Setter Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
-->
</ControlTemplate>
but my issue is how do i set up the trigger to show this when the ItemsSource property is null? I have tried a couple of different ways, and each way has given me the error message "Value 'ItemsSource' cannot be assigned to property 'Property'. Invalid PropertyDescriptor value.". My ComboBox xaml is this (including the attempted trigger):
<ComboBox Margin="112,35,80,0"
Name="MyComboBox"
Height="22.723"
VerticalAlignment="Top"
DisplayMemberPath="FriendlyName"
SelectedValuePath="Path"
TabIndex="160"
>
<Trigger>
<Condition Property="ItemsSource" Value="0" />
<Setter Property="Template" Value="{StaticResource LoadingComboTemplate}" />
</Trigger>
</ComboBox>
now should the trigger go on the ComboBox, or on the ControlTemplate? How do i access the ComboBox's ItemsSource property? Should i even be using a trigger?
Thanks!
Try putting {x:Null} for the value of the condition instead of 0.
Also I got it working by moving the Trigger to a style and modifing it slightly, see below.
<Style TargetType="ComboBox" x:Key="LoadingComboStyle">
<Style.Triggers>
<Trigger Property="ItemsSource" Value="{x:Null}">
<Setter Property="Template" Value="{StaticResource LoadingComboTemplate}" />
</Trigger>
</Style.Triggers>
</Style>
<ComboBox Style="{StaticResource LoadingComboStyle}" .... >
The reason it only works in a style, is that only EventTriggers are allowed in the triggers collection directly on the Framework Element. For property triggers (like above) you need to use a style (I learn something every day).
See FrameworkElement.Triggers
Note that the collection of triggers established on an element only supports EventTrigger, not property triggers (Trigger). If you require property triggers, you must place these within a style or template and then assign that style or template to the element either directly through the Style property, or indirectly through an implicit style reference.

WPF: Problem with Checkbox when binding datatrigger to property "Ischecked"

I have a checkbox in GridViewColumn which i use for show/change database value. The click event for the checkbox is used for change value in the database. For handling the state of property "IsChecked" I'm using datatrigger and a setter, se xaml code below:
<Style TargetType="CheckBox">
<Setter Property="IsEnabled" Value="True" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ID, Converter={StaticResource Converter}}" Value="true">
<Setter Property="IsChecked" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
The binding works great until I click the checkbox. After I clicked the checkbox for the first time the state of the property "IsChecked" don't updates if a manually in the Database change the value which i mapped to the property "IsChecked".
If I map for example the same value to the property "Content" of the checkbox the trigger works fine even after I've clicked the checkbox.
Does anyone no whats the problem is?
Shouldn't
<Style TargetType="CheckBox">
instead be:
<Style TargetType="{x:Type CheckBox}">
Edit:
you could try this:
<Style TargetType="{x:Type CheckBox}" >
<Setter Property="IsChecked" Value="{Binding Path=ID, Converter={StaticResource Converter}}" />
</Style>
You can try to add a second data trigger to set the checkbox to false. As I can see from your code you set the IsChecked only to true, but never to false.
In stead of using Click to determine the changes, perhaps you can use the Checked and Unchecked events ?

Resources