i'm developing a UI with WPF where i want to add buttons for the Undo/Redo inside the application actions. For example, if I input in TextBox1 a value, than another value, by pushing undo it turns back to the first value in textbox1.
I've tried to add a Command="ApplicationCommands.Undo" to the button but it turns grey and it is not clickable anymore on the UI:
<Button x:Name="undoBtn"
BorderBrush="#FFABADB3"
Background="{x:Null}"
Padding="5,0,5,0"
HorizontalAlignment="Left"
Width="100"
Height="25"
VerticalAlignment="Top"
Margin="15,130,0,0"
Click='undoBtn_Click'
Command="ApplicationCommands.Undo"
>
What am i doing wrong?
Thank you very much.
According to the documentation for the ApplicationCommands class:
The commands in the ApplicationCommands class [...] only represent the instance of the RoutedCommand and not the implementation logic for the command. The implementation logic is bound to the command with a CommandBinding.
[... However, m]any controls do provide implementation logic for many of the commands in the command library. For example, the TextBox class provides logic for the Paste, Cut, Copy, Undo, and Redo commands.
To utilize the implementation for the Undo/Redo commands provided by the TextBox class, set the target of the command to the TextBox element.
<TextBox Name="TextBox1"/>
<Button Content="Undo"
Command="ApplicationCommands.Undo"
CommandTarget={Binding ElementName=TextBox1}"/>
To answer your question, the Button is not enabled because the CanExecute property of the CanExecuteRoutedEventArgs for your CommandBinding's CanExecuteRoutedEventHandler is not set to true because your command does not have a target.
Related
There's a WPF class called SystemCommands. I've seen examples of these commands being used on buttons to perform common window tasks like maximize, minimize and close.
One of the examples I found looked like this (simplified):
<Window x:Name="MainWindow">
<Grid>
<Button Content="Close"
Command="{x:Static SystemCommands.CloseWindowCommand}"
CommandParameter="{Binding ElementName=MainWindow}" />
</Grid>
</Window>
When I start the application the button is disabled and I can't click it. Changing the IsEnabled property has no effect.
I managed to get the button to be enabled once, but I'm not able to reproduce it now. In any case, when it was enabled, nothing happened when I clicked it.
What must I do to get this button enabled and to actually close the window (or minimize/maximize)? I would really prefer it to be a XAML only solution if this is possible.
These are only predefined RoutedCommand(s) without any implementation. You must provide the implementation by yourself.
https://msdn.microsoft.com/en-us/library/system.windows.systemcommands
The commands in the SystemCommands class represent a set of common
commands that manage a Window. The properties in this class represent
RoutedCommand objects and do not provide the implementation logic for
the command. You can provide the logic for a command by binding the
command with a CommandBinding. Alternatively, the SystemCommands class provides static methods that implement the logic for the specified Window. You can pass a static method to a type that implements ICommand and that accepts a delegate. For more information, see the example in the InputBinding class.
I have a UI with a few controls.
Initially when form loads, search button will be disabled, once all
search criteria are given, search button will be enabled
automatically.
On click on search button, I want to call the method
using MVVM pattern and bind the result in grid
XAML:
<Button Name="btnGetDetails" Content="Get Details" Grid.Row="2" Command="{Binding SearchCommand}"/>
What code is required in model, view model and XAML?
Command will be executed only when the button will be clicked on. If you need to do something to the button then you should do it to the Window that contains the button (assuming your button is in a Window). Now if you want to stick with the MVVM pattern then you should not use the Window.OnLoaded, because that would put code in your code behind. One option is to use System.Windows.Interactivity, which you have download seperately. Here is what it will look like:
<Window x:Class="..."
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr
-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding ...}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Window>
As for what your Model, View and ViewModel should be, I think you should check out some tutorials on the web. There are some very good explanations on how to implement the MVVM pattern. I found this youtube video pretty informative myself:
http://www.youtube.com/watch?v=EpGvqVtSYjs
So some MVVM basics here. You're on the right track, just missing a step. Your Command implementation in your view model should (potentially) accept two inputs: An Action representing the executing code, and a Predicate that returns true/false on whether you can execute the code in the Action block. So, in your view model, define your command along the lines of (note: this is a sample from one of my projects):
this.executeCommand = new RelayCommand(this.OnExecuteClicked, this.OnCanExecuteChanged);
The OnCanExecuteChanged method will return a bool based on whatever criteria you set up. So, if you want the submit button enabled when property A and property B have been properly set up, then return true, else return false. The internal workings of your command implementation will take care of the rest. Do a search for a RelayCommand implementation (if you don't have it already) or a DelegateCommand for further samples.
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 want to initiate a bound command, but I don't want to use a Button on my UserControl. In effect the UserControl is itself a Button. When it is clicked anywhere on its surface I want to initiate a bound command. Is there a way to give a UserControl a command?
In a side note: one command for one control and only a few certain out-of-the-box controls? This all seems a little clunky. I'm starting to think that MVVM is impractical. I can decouple my UI just fine with Interfaces and OOP. Anyway, I still have hope.
Also, I'm not willing to hack anything or use an expensive workaround. If I can't do this, I'm abandoning MVVM.
Take a look at the ICommandSource interface here: http://msdn.microsoft.com/en-us/library/system.windows.input.icommandsource.aspx. If you want a control to have a command, then your control should implement this interface. Examples of controls that implement this interface are ButtonBase and MenuItem. Hope this helps.
If your UserControl is essentially a Button, why are you writing your own UserControl instead of using the Button class?
To add more info, here's what you do:
Subclass Button, put any extra DependencyProperties that you need in there - it should be a very empty class (you could even have something like public class MyCoolButton : Button { }
Add a Style whose TargetType is MyCoolButton - don't name the style so it applies to all MyCoolButtons
Override the default Template of the style, then paste in your Xaml code. You might have to do some work here to handle the "Normal / Pushed / Disabled" states. If you're using v4.0, you can use VSM here.
I will agree with Paul Betts.
Quite often I create my own ListBoxItemContainerStyle using a button as the top container with nothing but a propertyless content presenter in it. This allows me to use the buttons functionality (like Command) without having the Windows chrome on it.
Putting it in the ListBoxItemContainerStyle also lets me make it so that when it is clicked it does not display the normal dotted border (FocusVisualStyle={x:Null}).
Are you using Visual Studio or Expression Blend to do your styling?
Additionally, some MVVM frameworks provide an interface for adding a command-ish ability to controls other than buttons. Caliburn has a pretty rich command pattern. I am not sure if it allows binding commands on non-button controls, however.
The OP asked for an example of how you could use a button control, but with the content properly filling the entire button. You can do this using the ContentAlignment properties:
<Button HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<Button.Content>
<Grid IsHitTestVisible="False">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Row0" />
<TextBlock Grid.Row="1" Text="Row1" />
</Grid>
</Button.Content>
</Button>
This creates a button with two labels spaced using a Grid control. I mark the Grid to turn off HitTestVisible, as you have to decide which controls should interact like the button and which should interact like controls. For instance, you might have an embedded TextBox that you want to be clickable without clicking the button, in which case it should have HitTestVisible=True.
WPF supports layers and transparency :
Panel.ZIndex
You can create anything that supports commanding on a superior transparent layer, the size you want, to act as a button.
I have a DesignerCanvas (derived from canvas) that I can add UIElements to, then drag\drop\move\group and move them around.
On the toolbar I have a button that is bound to a group command.
<Button Margin="0,3,0,3" Padding="5" HorizontalContentAlignment="Left"
Command="{x:Static s:DesignerCanvas.Group}"
CommandTarget="{Binding ElementName=DesignerCanvas}">
The problem that I have is that I can have a control that also contains a DesignerCanvas. So there are nested canvas's, and I want the GroupCommand on the toolbar to apply to the canvas that is in focus. In the above binding it is binding only to the root canvas.
I suppose I could track the current canvas and expose it in the viewmodel for the binding, but I'd prefer to avoid tracking the activecanvas.
Any suggestions for a creative binding here?
Thanks,
jeff
Is GroupCommand a RoutedCommand? Assuming it is, I would expect that you would get the behavior you want by removing the CommandTarget property assignment.