Force context menu to recreate child controls each time it opens - wpf

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>

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

Use DataTrigger to hide/show WPF TreeView ContectMenu

I have a TreeView in my WPF application and I want to show or hide the context menu depending on the type of the treeviewItem. TreeView is databound and populated using a HierarchicalDataTemplate. I can disable the context menu items in code in the rightmouse event.
But I want this to be done in XAML instead. What I tried is;
<Grid.Resources>
<ContextMenu x:Key="MyContextMenu">
<MenuItem Name="Menu1" Header="Add " Click="AddNew_Click" ></MenuItem>
<MenuItem Name="Menu2" Header="" Click="Menu2_Click"></MenuItem>
</ContextMenu>
</Grid.Resources>
In side the Treeview I have this code
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding Document.DocumentType}" Value="P">
<Setter TargetName="icon" Property="Source" Value="../Images/P.png"/>
*<Setter Property="ContextMenu" Value="{StaticResource MyContextMenu}"/>*
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
But this gives runtime error 'object reference not set to an instance of object'. You can see the image is set with data trigger when DocumentType is 'P' and I want the context menu to be visible/enabled only when DocumentType is 'P' and hide/disabled otherwise.
Can this be done?
Another person had the same issue and he had gotten this answer from Microsoft forum. It doesn't use triggers, however the context is dynamic. I can use a variation of this to show my context menu only when I need it to depending on the bound data.
here is the link
I will mark this as answered, so it might help someone in the future.

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).

WPF Button Visibility

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.

Popup vs. Visibility toggle

I have a couple of views that I display as overlays on the main window by binding the visibility to a boolean property in my ViewModel.
The main window looks something like this:
<Grid>
<vw:MainContentView/>
<!-- Overlays (normally invisible) -->
<vw:NotificationsView/>
</Grid>
The 'NotificationsView' has a style that looks like this:
<Style x:Key="NotificationsView" TargetType="UserControl">
<!-- snipped -->
<Style.Triggers>
<DataTrigger Binding="{Binding IsNotificationsViewVisible}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsNotificationsViewVisible}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
I am wondering whether it might be preferable to use a Popup with the 'IsOpen' property bound to the 'IsNotificationViewVisible' property in the ViewModel, rather than toggling the visibility of the view directly:
<Grid>
<vw:MainContentView />
<!-- Popups (normally invisible) -->
<Popup IsOpen="{Binding IsNotificationsViewVisible}">
<vw:NotificationItemsView/>
</Popup>
</Grid>
Are there any reasons I'd want to use one approach over the other (memory usage or otherwise)? Both approaches seem to work just fine - the Popup comes with a couple of free animations but otherwise looks the same.
If you're displaying content on an already existing window, you should probably use the Visibility approach. The Popup acts as a mini-window that can initially position itself based on the location of elements in the main window. That means that it can go outside the bounds of the main window and won't move around when you move the main window. It also doesn't effect the layout of other elements in the window. I imagine it also has some overhead associated with this, but I have not run any exact numbers.
As a bonus, I'll throw in a suggestion: you could use a converter to make Visibility binding easier.

Resources