WPF Debugging datatriggers? - wpf

I am trying to do something very simple. I have a ToggleButton.IsChecked property bound to a bool. I want the background to toggle between red(false) and green(true). But for some reason it seems to be toggling between red and no background. I used a converter to check if I am getting proper notifications from the source and I am, so not sure why one trigger(false/red) works and the other(true/green) doesnt. Also would like to hear how people debug these kind of issues. Thanks!
Here is the code.
<DataTemplate x:Name"Flipper">
<StackPanel>
...
<ToggleButton IsChecked="{Binding Path=BoolValue,
Converter={StaticResource converter}}"
Name="onoff" >
</ToggleButton>
...
<StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=onoff,Path=IsChecked}"
Value="True">
<Setter TargetName="onoff" Property="Background" Value="Green"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=onoff,Path=IsChecked}"
Value="False">
<Setter TargetName="onoff" Property="Background" Value="Red"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
Update: I changed the togglebutton to a checkbox and it works. No idea why...

Try using WPF Inspector:
https://wpfinspector.codeplex.com/
Once you attach to your running WPF application, highlight the element in question by holding down ctrl + clicking on it. Then, select the element in the visual tree (might be a parent) that contains the trigger. Click on the triggers tab and you can see the current evaluation (e.g. True == True). If the datatrigger condition is met, the little icon will be orange (lit).

It looks ok to me, can you try altering the converter to return "red" or "green" rather than True/False (and alter the trigger accordingly). I have seen some wierd behaviour with WPF triggers when using NULL or Booleans in that it "unsets" the property if it's the opposite of your trigger value, rather than using another trigger value.
As for debugging them.. I'd love to know if there's a better way than the hack and hope methods I generally use for XAML debugging :D

Related

How to put a tooltip to a button for enabling and disabling in WPF

I want to put a tooltip to a button for enabling and disabling in WPF. I have mentioned the tried code below. But My tried code does not solve my problem. I have no idea should I use the separate property for this.
Code:
<dc:GeometryButton
Grid.Column="11"
Command="{Binding Path=GeneratePrintTemplateFilesCommand}"
Geometry="{StaticResource {x:Static dc:Geometries.Print}}"
ToolTip="{Binding Path=GeneratePrintTemplateFilesFeatureToolTip}"
Style="{StaticResource FormBuilderClient_TopToolbarGeometryButton_Style}"/>
I need your help to solve this. Thank you.
Same tool tip when disabled
If you want to show the same tool tip for both the enabled and disabled state of the button, you have to set the ShowOnDisabled property of the ToolTipService to True on your button.
ToolTipService.ShowOnDisabled="True"
Different tool tips through binding
If want to show different tool tips by changing the bound property GeneratePrintTemplateFilesFeatureToolTip in your view model on button click e.g. in your GeneratePrintTemplateFilesCommand, the first solution also works. However, you must implement INotifyPropertyChanged in this case, otherwise the button will not get notified of the changed tool tip text.
Different tool tips with style
An alternative for showing different tool tips for the enabled and disabled states of your button is to add a trigger to the Style of the button and make it depend on the IsEnabled property. You can merge this with your existing style. Note that I use two different properties to bind to, one for enabled and one for disabled. In practice, you would rather use static resources here, instead of properties on a view model, because they do not change here.
<Style x:Key="FormBuilderClient_TopToolbarGeometryButton_Style"
TargetType="{x:Type dc:GeometryButton}"
BasedOn="{StaticResource {x:Type dc:GeometryButton}}">
<Setter Property="ToolTip"
Value="{Binding GeneratePrintTemplateFilesFeatureToolTipEnabled}"/>
<Style.Triggers>
<Trigger Property="IsEnabled"
Value="False">
<Setter Property="ToolTip"
Value="{Binding GeneratePrintTemplateFilesFeatureToolTipDisabled}"/>
</Trigger>
</Style.Triggers>
</Style>
Make sure to remove the tool tip property from the button control itself and add the ShowOnDisabled property setting from above., otherwise your tooltip either will not change or not be displayed in disabled state.
<dc:GeometryButton Grid.Column="11"
Command="{Binding Path=GeneratePrintTemplateFilesCommand}"
Geometry="{StaticResource {x:Static dc:Geometries.Print}}"
ToolTipService.ShowOnDisabled="True"
Style="{StaticResource FormBuilderClient_TopToolbarGeometryButton_Style}"/>

Style Triggers not working when object is bound to other object

I am having a problem with the style of a few items that are bound to a set of radio buttons. Basically, I have the following code for my styles:
<Window.Resources>
<Style x:Key="boxStyle" TargetType="TextBox">
<Setter Property="Background" Value="Black"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="Blue"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
Then I have two radio buttons as shown here:
<RadioButton Name="optionA" IsChecked="True">Option A</RadioButton>
<RadioButton Name="optionB'>Option B</RadioButton>
And two text boxes as shown here:
<TextBox Style="{StaticResource boxStyle}" IsEnabled="{Binding ElementName=optionA, Path=IsChecked}"/>
<TextBox Style="{StaticResource boxStyle}" IsEnabled="{Binding ElementName=optionB, Path=IsChecked}"/>
The binding works correctly (when Option A it checked, one box is enabled and the other is not). However, when either of the boxes becomes disabled, it does not follow the style defined above. The background goes to white no matter what I change the style color to.
Anyone have any ideas? Thanks.
The color used when disabled is hard-coded in the template as far as i know, you cannot easily change it unless it references a system-color in which case you can override.
The default Aero theme uses a ListBoxChrome control, not sure if that can be made to change its background accordingly, it has no template so it might be hard to modify it. You could of course throw it out and use whatever you want (which you can modify).

Hover effect for a Control that resides if a ContextMenu is opened

I want to add a hover effect for a WPF-Control.
For this, I created a Style-Trigger that changes the Background-Brush of the control if IsMouseOver is true. This works fine, however if I open a ContextMenu from the control, IsMouseOver becomes false and the hover effect stops until the ContextMenu is closed.
I also tried a combination of MouseEnter and MouseLeave, but with this, there is the same behaviour. If the context menu` is opened, MouseLeave will be fired.
I understand why I can not do it like this, but I don't see a nice way to solve my requirement. Has anyone did already something like this?
The issue can be resolved by the creation of a second trigger, that checks if the attached ContextMenu is opened:
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource Hover_Brush}"/>
</Trigger>
<DataTrigger Binding="{Binding ContextMenu.IsOpen,RelativeSource={RelativeSource Mode=Self}}" Value="True">
<Setter Property="Background" Value="{StaticResource Hover_Brush}"/>
</DataTrigger>
Caveat
The above XAML works fine, but has one issue: If the style is used for more than one item and the controls ContextMenu is shared, the hover effect will be activated on all items if the context menu is opened for a control.
Therefore, the context menu must not be shared. If it is defined in a resource, use the x:Shared="false" property to disable sharing. If it is directly defined under the control, this problem does not occur.

Binding a Style DataTrigger to a custom ICommand's status property

I have a custom implementation of WPF's ICommand, that executes its bindings in a BackgroundWorker, so that the UI stays responsive.
I would like to display a custom effect while the bindings are being executed. For now, the effect is simplified to setting command source's IsEnabled property to False. Later, our designer will come up with some nice progress-style animation.
Here's an example of what I'm trying to do, that works (sort of):
<Button Width="80"
Command="{x:Static Member=local:AppCommands.Test}"
DataContext="{x:Static Member=local:AppCommands.Test}">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="IsEnabled" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsExecuting, Mode=OneWay}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
As evident, my ICommand contains an IsExecuting property, which is set to True while the BackgroundWorker does its thing with the bindings, consequently disabling the button in the UI.
Unfortunately, having to explicitly set the button's DataContext to command instance prevents me from referring to the original DataContext in cases like this one:
<Button Width="80"
Command="{x:Static Member=local:AppCommands.ParamTest}"
CommandParameter="{Binding Path=SelectedItem}"
DataContext="{x:Static Member=local:AppCommands.ParamTest}">
Here, the CommandParameter should bind to the window's DataContext (which is set to an instance of my view-model), but instead it binds to the command which knows nothing about SelectedItem.
There are probably more ways to solve this, and I'm interested to hear all of them. I myself have been thinking along the lines of using an attached property to replace the direct binding to command's IsExecute and with it the need for setting the DataContext, but I'm not yet sure how to do that.
Any advice is most welcome. Thank you!
For now, I've come up with this simple solution:
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Command.IsExecuting, Mode=OneWay}" Value="True">
It does what I wanted so I'm happy. If anyone thinks there's a better way, I'm still interested, though.

Select All Checkbox in XAML using trigger?

I'd like to implement a select all checkbox in xaml.
I have several (templated) checkboxes in a listview. Then I have a checkbox outside of the listview, which I want to have a "select all"-behaviour.
I could easily solve the problem in my ViewModel, however, I think it would be more elegant to do this in xaml, since the select all checkbox doesn't (directly) have anything to do with my ViewModel.
The code looks something like this:
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<CheckBox Content="Globale Eingabe"
Name="SelectSingle"
IsChecked="{Binding IsChecked}">
</CheckBox>
</DataTemplate>
<ListView.ItemTemplate>
</ListView>
<CheckBox Name="SelectAll" />
As you see the IsChecked Property of the SelectSingle is already bound to my ViewModel. So I reckon I need a trigger to manipulate the state of the checkbox.
Now I already tried sth like this:
<CheckBox Content="Globale Eingabe"
Name="SelectSingle"
IsChecked="{Binding IsChecked}">
<CheckBox.Triggers>
<Trigger SourceName="SelectAll" Property="IsChecked" Value="True">
<Setter TargetName="SelectSingle" Property="IsChecked" Value="True"/>
</Trigger>
</CheckBox.Triggers>
</CheckBox>
or sth like this:
<CheckBox Content="Globale Eingabe"
Name="SelectSingle"
IsChecked="{Binding IsChecked}">
<CheckBox.Triggers>
<DataTrigger Binding="{Binding ElementName=SelectAll, Path=IsChecked}"
Value="True">
<Setter TargetName="Check"
Property="IsChecked"
Value="True"/>
</DataTrigger>
</CheckBox.Triggers>
</CheckBox>
I also tried the same thing within a style, but to no avail. I always obtain an error, sth along the lines of "static member "IsCheckedProperty couldn't be found in type "ContentPresenter"".
Now that sounds as if the Target/SourceName binding wouldn't work, but why?
Is there something that I am missing?
I think that you should put the Check All logic in the ViewModel after all. In this Code Project article, WPF Guro Josh Smith solves similar problem (in his case it's TreeView and not ListView) in the ViewModel with the following title: "Putting the Smarts in a ViewModel".
I think it'd be easier to implement and debug this logic in the ViewModel, than to do some complicated MultiBinding that you wouldn't know where it'll bite you.
Last note - I'd always follow Josh's advice :-)
Torsten, I am sorry if I didn't understand what you've tried already, but you need to bind the IsChecked property of the CheckBoxes inside the ListView to the IsChecked property of the CheckBox outside it using:
IsChecked="{Binding Path=IsChecked, Mode=OneWay,ElementName=OutsideCheckBox}"

Resources