WPF Button Visibility - wpf

I am using MVVM architecture to develop a WPF application...
So far everything has been going fine.
I have run into an issue with binding visibility. I want to minimize writing code in the code behind if i can but if it's REQUIRED then I don't mind doing it.
I have a ViewModel. THis model exposes a boolean and 2 commands. A connect command, a disconnect command, and a DeviceCurrentlyConnected Bool.
Basically I have decided to make 2 buttons but have the button visibility based on the boolean.
So i have had a hard time with this. I tried styles with triggers for a long time.
<Button Visibility="Hidden" Content="{x:Static UIStrings:ClientStrings.DeviceBar_DisconnectCommandName}" VerticalAlignment="Center" HorizontalAlignment="Center" Height="{Binding ElementName=this.Content, Path=DesiredHeight}" Margin="10" Name="Disconnect" Command="{Binding DisconnectCurrentDeviceCommand}">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding DataCotext.DeviceConnected, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I can not get styles to work at all.
Basically the functionality that I want is:
DeviceConnected = false:
Display a button with content Connect and command bound to the ConnectCommand.
DeviceConnected = true:
Display a button with content disconnect and command bound to the DisconnectCommand.
for a button to be displayed and bound to the connect device when no device is currently connect and for a button to be displayed when a device is connected that is bound to the disconnect command and to say the word disconnect.

Write up a bool to visibility converter and then use the converter on your buttons. Five minute recipe for a decent BoolToVisibilityConverter is a good post to read up on creating/using a visibility converter.
What I've done in the past is use a bool to visibility converter and passed in the button's IsEnabled property as the parameter to the converter. Since the button is dis/enabled by the command in the model with the CanExecute method, you can then use the IsEnabled property to set the visibility of the button with the converter.

The reason that your trigger doesn't work is that the style is overridden by the attribute on the button itself.
You can use a converter as Metro Smurf suggests, alternatively you can move the visibility attribute into the style so that the trigger works properly
Just add:
<Style.Setters>
<Setter Property="Visibility" Value="Hidden" />
</Style.Setters>
To the style and then remove the attribute.

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}"/>

WPF trigger can't change a property in mvvm

I wanted to make it happened to change property in ViewModel using Trigger tag in xaml.
The code I made was like this.
<Grid x:Name="LogoGrid">
<Grid.Style>
<Style TargetType="Grid">
<Setter Property="Height" Value="{Binding LogoHeight, Mode=TwoWay}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualHeight, Converter={StaticResource ImageHeight}}" Value="False">
<Setter Property="Height" Value="150"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Image Source="/Resources/Logo/Logo.png" Style="{StaticResource GameWindowLogoStyle}"/>
</Grid>
I bound data to LogoHeight property in ViewModel and I wanted to set this property to 150 when parents grid is big enough to show Logo Image.
It works fine in the UI. but it didn't change LogoHeight property.
It is the same things keep happening when I use animation with Storyboard tag.
Is it normal things that propery can't be changed by Trigger tag or animation in the Storyboard tag.
Please tell me the way if there is a way to change property in Trigger tag or Storyboard tag.
Thank you.
A Setter in a Style cannot set the property of a view model. It can only set a property of the element to which the Style is being applied, i.e. the Grid in this case.
You may be able to work around this by using a Storyboard that animates the source property:
Setting a ViewModel boolean property inside a storyboard

Force context menu to recreate child controls each time it opens

I have a context menu which contains a both a OneTime, one way binding and a second, non-OneTime two way binding to the same property. The goal is to have a color editor which displays the initial color value, and allows the user to change the selected value while still being able to compare it to the original.
This works well the first time the context menu is opened, but the menu doesn't seem to fully recreate itself each time it is opened (cached?). Instead, it "remembers" the original binding value, instead of doing another OneTime binding from the source to get the new "initial" value.
Is there a way to force a context menu to fully recreate its contents each time it is opened?
I was able to quickly do this by creating a Style for the ContextMenu that sets its DataContext to null when it is hidden. This will cause the Bindings to re-run when it is opened, as they will have a new source. If you set the DataContext explicitly for the ContextMenu, you'll have to move that to a setter:
<ContextMenu>
<ContextMenu.Style>
<Style TargetType="{x:Type ContextMenu}">
<Style.Triggers>
<Trigger Property="IsOpen" Value="False">
<Setter Property="DataContext" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</ContextMenu.Style>
<MenuItem Header="{Binding Color, Mode=OneTime}" />
</ContextMenu>

WPF Style Trigger Not Working?

Good Day,
I have a TextBlock element with a black background and text with a black foreground color. I do not want my users to see the text until a task is completed. Then the text will turn into a greenish color.
My style trigger in xaml looks like:
<Style x:Key="DataImportCompletedStyle" TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#FF000000" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsImportCompleted}" Value="True">
<Setter Property="Foreground" Value="#FF99F999" />
</DataTrigger>
</Style.Triggers>
</Style>
My TextBlock looks like:
<TextBlock x:Name="ImportStatusMesage"
Grid.Row="3"
Margin="5,0,5,10"
Background="Black"
FontSize="18"
Foreground="#FF000000"
Style="{StaticResource DataImportCompletedStyle}"
Text="Data Import Completed" />
And my code behind for the IsImportCompleted boolean property is:
private bool isImportCompleted;
public bool IsImportCompleted
{
get { return isImportCompleted; }
set
{
isImportCompleted = value;
System.Diagnostics.Debug.WriteLine("Import Process Completed...OnPropertyChanged");
OnPropertyChanged("IsImportCompleted");
}
}
which does implement INotifyPropertyChanged. The task works fine and updates the IsImportCompleted property as I am seeing my message in the Output window, but the text doesn't change color.
I thought by using INotifyProperty that the UI would update itself.
I'm using Snoop and verified that the IsImportCompleted is set to true. But still no text color change.
Any advice,
TIA,
coson
I am quoting from the comment of the Asker. which according to him, this solved his problem
Never mind, I figured it out. I'm setting the Foreground property in my XAML which will always override what I set in the trigger based on the precedence rules. Once I took out the Foreground property definition in my TextBlock tag, everything worked!

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.

Resources