I have a string property in my ViewModel/Datacontext and want a simple button that copies its contents to the clipboard. Is this possible to do from XAML, or I do I need to handle the button click event (or use an ICommand) to accomplish this? I thought the following would work, but my button is always greyed out:
<Button Width="100" Content="Copy" Command="ApplicationCommands.Copy"
CommandTarget="{Binding MyStringProperty}"/>
The ApplicationCommands are expecting to be in a Toolbar or Menu which will give them FocusScope based on RoutedUICommands. If your button is outside a Toolbar or Menu, then you need to explicitly declare the focus scope:
<Button
Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"
Command="ApplicationCommands.Copy"
FocusManager.IsFocusScope="True"/>
The CommandTarget is used to declare which element will provide the FocusScope which means that the Copy button will only be enabled whenever the element declared in the CommandTarget has focus, and in the case of copy, has text highlighted:
<Button
Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"
Command="ApplicationCommands.Copy"
CommandTarget="{Binding ElementName=MyElement}" />
In answer to your specific question, you'd need to intercept the ApplicationCommands.Copy command to get/set your ViewModel's MyStringProperty; and to be honest, I'm not sure where to even start to figure that one out. Maybe someone smarter around here could provide that piece of the puzzle.
Related
i have option button binded to some property and everything is working fine but now i want to achieve same thing on button click .
is there any way to pass click event to button click?my option button xaml code is as follows
<RadioButton Content="Any connection"
x:Uid="saifeconnect.settings.autoconnectto.any.radiobutton"
Margin="0,5"
GroupName="AutoConnect"
IsChecked="{Binding Path=AutoConnectMode,
Mode=TwoWay,
Converter={StaticResource enumConverter},
ConverterParameter=kAny}" />
If possible then make use of RelayCommand. Follow the given tutorial, best for RelayCommand.
https://www.codeproject.com/Articles/126249/MVVM-Pattern-in-WPF-A-Simple-Tutorial-for-Absolute
Sorry for the title, I just don't know how to explain it in one sentence.
So here is my goal: I need to have a boolean in my ViewModel define the visibility for a control (border).
I know I can achieve this with a BooleanToVisibilityConverter, but there is a little more to it. I want a button on my UI to be shown if the control is not visible. Once that button is pushed, then I want the boolean in my ViewModel to be TRUE and then I want the control to be visible and the button that was just pushed to be collapsed. Once that control is visible, I would like a button within that recently visible control to make the control collapsed and then make the original button visible.
Basically, there are two buttons: 1 to make visible (then collapse itself) and the other is to collapse its container and then make the first button visible.
I am trying to do all this with MVVM so if I can avoid code behind in my View that would be ideal!
Since you're using ICommands on your viewmodel, this should work...Assume your commands are "ShowBorderCommand" and "HideBorderCommand" and the property on your viewmodel is "ShowBorder"
<ConverterNamespace:BooleanToVisibilityConverter x:Key="BoolToVis"/>
<ConverterNamespace:ReverseBooleanToVisibilityConverter x:Key="BoolToCollapse"/>
<Border Visibility="{Binding ShowBorder, Converter={StaticResource BoolToVis}}">
<Button Command="{Binding HideBorderCommand}"/>
</Border>
<Button Command="{Binding ShowBorderCommand}" Visbility="{Binding ShowBorder, Converter={StaticResource BoolToCollapse}}"/>
My WPF Converters library has a BooleanToVisibilityConverter that allows reverse conversions, as well as allowing the use of Hidden instead of Collapsed:
<con:BooleanToVisibilityConverter x:Key="ReverseBooleanToVisibilityConverter" IsReversed="True"/>
<Button Visibility="{Binding SomeProperty, Converter={StaticResource ReverseBooleanToVisibilityConverter}}"/>
I have a custom command and I try to execute them from the context menu, but they are always displayed as disabled unless I click any button on the UI (buttons do not have anything to do with commands).
After clicking a button, commands start to be displayed correctly (when they are unavailable they get disabled and enabled if available).
Edit: it turns out that it is not the button click which makes command work correctly, but button or other controls in focus (e.g. if I tab into a control this also enables my commands).
Here is the code for commands:
<Window.InputBindings>
<KeyBinding Command="{x:Static local:MainWindow.Quit}" Key="Q" Modifiers="Ctrl"/>
<KeyBinding Command="{x:Static local:MainWindow.Disconnect}" Key="D" Modifiers="Ctrl"/>
</Window.InputBindings>
<Window.ContextMenu>
<ContextMenu Opacity="95">
<MenuItem Header="Quit Application Ctrl + Q" Command="{x:Static local:MainWindow.Quit}"/>
<MenuItem Header="Disconnect from the pump Ctrl + D" Command="{x:Static local:MainWindow.Disconnect}"/>
</ContextMenu>
</Window.ContextMenu>
Here is the commands CanExecuteMethod:
public static RoutedCommand Quit = new RoutedCommand();
private void QuitCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
e.Handled = true;
}
This issue is due to the ContextMenu being on a separate Visual and Logical Tree to that of the Window and its Controls.
For anyone still looking for an answer to this issue - After trawling the internet I have found the most effective answer to be to include the following in any declaration of a MenuItem that needs its commands to be heard by it's "owner".
In layman's terms; if you want the commands of your context menu to be heard by the thing you're right clicking on. Add this code:
CommandTarget="{Binding Path=PlacementTarget,
RelativeSource={RelativeSource AncestorType=ContextMenu}
}"
Example:
<ContextMenu>
<MenuItem Header="Close" Command="Application.Close"
CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
</ContextMenu>
This will also work within Templates (something I found a lot of another solutions not to support). Here is an explanation of the meaning of the statement taken from elsewhere (I'm appalling at explaining things):
Every FrameworkElement has a DataContext that is an arbitrary object. The default source for a data binding is that DataContext. You can use RelativeSource.Self to change the source for a binding to the FrameworkElement itself instead of its DataContext. So the RelativeSource part just moves you "up one level" from the DataContext of the FrameworkElement to the FrameworkElement itself. Once you are at the FrameworkElement you can specify a path to any of its properties. If the FrameworkElement is a Popup, it will have a PlacementTarget property that is the other FrameworkElement that the Popup is positioned relative to.
In short, if you have a Popup placed relative to a TextBox for example, that expression sets the DataContext of the Popup to the TextBox and as a result {Binding Text} somewhere in the body of the Popup would bind to the text of the TextBox.
I honestly hope that this information saves someone who's new to WPF the headache I've gone through this weekend... though it did teach me a lot!
Completely different track, now:
there is indeed something special about the ContextMenu as the carrier for commands:
the menu is not regarded as part of the window and therefore does not behave like an element in its visual tree would.
There are different solutions for your problems defined here:
http://www.wpftutorial.net/RoutedCommandsInContextMenu.html
The easiest approach seems to be adding this to your XAML (for the window):
FocusManager.FocusedElement="{Binding RelativeSource={x:Static RelativeSource.Self}, Mode=OneTime}"
I just ran into this while trying to implement a custom context menu for AvalonDock. None of the solutions suggested above worked for me.
I got the context menu working by explicitly registering my command handlers on the ContextMenu class in addition to the main widow. The function below is a helper I used for command registration.
void RegisterCmd(RoutedCommand command, ExecutedRoutedEventHandler handler, CanExecuteRoutedEventHandler canExecute)
{
var binding = new CommandBinding(command, handler, canExecute);
this.CommandBindings.Add(binding);
CommandManager.RegisterClassCommandBinding(typeof(ContextMenu), binding);
}
There is probably some change "behind the scenes" that would normally enable the commands, but the view is not aware of this change.
One would need to see the Command-implementations to give more precise hints.
You can either make anything that changes your command-enable-state notify the view or manually trigger a command-refresh via CommandManager.InvalidateRequerySuggested(), for example when the context-menu opens.
WPF ICommands work that way; they requery their CanExecute function whenever something in the view changes (e.g. PropertyChanged-event is fired or a button is clicked), but they don't requery if they have no reason to.
This is a known bug. If there is no focused element in the window's main focus scope, the CanExecute routing will stop at the ContextMenu, so it will not reach to the CommandBinding on the Window, one workaround is to bind MenuItem's CommandTarget to the main window, as following code demonstrates:
<Window.ContextMenu>
<ContextMenu >
<ContextMenu.Items>
<MenuItem Command="ApplicationCommands.Open"
CommandTarget="{Binding Path=PlacementTarget,RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"/>
</ContextMenu.Items>
</ContextMenu>
</Window.ContextMenu>
I've used a control template to change the appearance of a button in a trivial way. It now looks different, but does not behave like a button. There are really two problems:
The button's command is never executed
After clicking on the button, it appears selected (i.e., the ellipse turns into an ugly blue rectangle)
Here's the general idea:
<Button Command="{x:Static commands:...}"
CommandParameter="{Binding}">
<Button.Template>
<ControlTemplate TargetType="Button">
<Ellipse Fill="{Binding ...}"
.../>
</ControlTemplate>
</Button.Template>
</Button>
There's no reason this should be happening. I put together a test using ApplicationCommands.Copy and the command fired just fine. Could be your CommandBinding isn't working properly.
I also didn't see this based on copying your sample XAML and just setting Fill="Green". You can try setting FocusVisualStyle="{x:Null}" on the Button.
The problem turned out to be that Fill was bound to a value that could be null. If the Fill brush is null rather than transparent, then there's nothing to click and the command doesn't get executed. As Drew mentioned, with a solid fill, the button works correctly.
Takeaway lesson: if you want to hide your shape but still have it respond to user interaction, use a transparent brush, not a null brush.
I had a similar problem with a custom templated button:
<my:UniButton Command="{Binding MyCommand}"/>
The binding didn't work until adding a RelativeSource:
<my:UniButton Command="{Binding MyCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=my:CustomPanel}}"/>
where CustomPanel is a control where my button lies.
Withal I had a simple button on the same panel, but it worked fine even without RelativeSource.
I need to set a control's background to the color of the parent's background in XAML. Why not simply make the background transparent? It's a button with a drop shadow, so I need to set the background; otherwise, the drop shadow shows through.
So, from my control's markup, how do I set the Background property equal to whatever the parent (host) Background is? Thanks for your help.
You should be able to set the binding using:
<Button Background="{Binding Path=Background, RelativeSource={RelativeSource Mode="FindAncestor" AncestorType="{x:Type Control}" AncestorLevel="1"}}" />
Since Background is defined for any "Control", this should grab the control one ancestor up the tree, and use it's background.
Another option to consider would be to just make a button style that shows the background as transparent, but actually still draws the drop shadow/border. This would allow it to work on any UIElement.
I am going to leave Reed's answer as accepted, since it does answer my original question. But I discovered that I actually need to bind to the window in which the button is hosted. Here is markup to do that:
<Button Background="{Binding Path=Background, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">My Button</Button>