I created a button whose commandparameter is set and command using a class that implements ICommand interface. But my button is disabled. Why is that? I got this code from here: ICommand is like a chocolate cake
<Window x:Class="ICommand_Implementation_CSharp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ICommand_Implementation_CSharp"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid>
<Grid.Resources>
<local:HelloWorldCommand x:Key="hwc" />
</Grid.Resources>
<Button Command="{StaticResource hwc}" CommandParameter="Hello"
Height="23" HorizontalAlignment="Left" Margin="212,138,0,0"
Name="Button1" VerticalAlignment="Top" Width="75">Button</Button>
</Grid>
</Grid>
and my class is
class HelloWorldCommand:ICommand
{
public bool CanExecute(object parameter)
{
return parameter != null;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
MessageBox.Show(parameter.ToString());
}
}
Well, this is very-very simple implementation of ICommand.
As #JleruOHeP says, partially problem can be solved by swapping setters of Command and CommandParameter. But this is ugly way, because you have to remember the sequence every time.
More correct way is to tell CommandManager to re-query states of command:
public class HelloWorldCommand : ICommand
{
public bool CanExecute(object parameter)
{
return parameter != null;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
MessageBox.Show(parameter.ToString());
}
}
Now the sequence of setters is indifferent.
To understand how CommandManager works, you can read this nice article from Josh Smith.
The simplest answer - switch places of Command and Command parameter:
<Button CommandParameter="Hello" Command="{StaticResource hwc}" .../>
But better one is given by #Dennis
In my case it was the CommandParameter type that was causing the issue. My button was simply bound like this:
<Button Content="New" Command="{Binding NewCommand}" CommandParameter="False" />
The underlying NewCommand is a RelayCommand<bool>. Somehow XAML was not able to translate False to bool. (Note that it does work for many built-in types and properties; maybe some TypeConverter or something at action there).
Solution was to simply spoon-feed XAML about the real underlying type of CommandParameter, like this:
<Button Content="New" Command="{Binding NewCommand}">
<Button.CommandParameter>
<sys:Boolean>
False
</sys:Boolean>
</Button.CommandParameter>
</Button>
You have to import sys namespace at the top of your XAML file, like this:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Hope this helps someone down the road.
Related
I'm learning WPF.
In one of the exercises, I have a TextBox and buttons Cut and Paste. The following is enough to implement Cut and Paste functionality:
XAML:
<DockPanel>
<WrapPanel DockPanel.Dock="Top" Margin="3">
<Button Command="ApplicationCommands.Cut"
CommandTarget="{Binding ElementName=txtEditor}"
Width="60">
_Cut
</Button>
<Button Command="ApplicationCommands.Paste"
CommandTarget="{Binding ElementName=txtEditor}"
Width="60" Margin="3,0">
_Paste<
/Button>
</WrapPanel>
<TextBox AcceptsReturn="True" Name="txtEditor" />
</DockPanel>
When pressed, the button Cut executes the ApplicationCommands.Cut on the TextBox with name txtEditor. When needed, the button will ask the TextBox with name textEditor if it can execute a Cut command, and when pressed it will order the textEditor to execute the Cut command.
Fairly straightforward. It works fine.
Just for Fun, I'd like to implement another button: Clear. When pressed it should clear the TextBox. The Textbox class has a method Clear.
<Button Command="ApplicationCommands.Clear"
CommandTarget="{Binding ElementName=txtEditor}"
Width="60">
Clear
</Button>
Alas, this won't work. ApplicationCommands doesn't have a Clear. Should I implement a custom command, as suggested in this example?
I tried the following:
I implemented CanExecute and Executed methods in my window:
public partial class CustomCommandSample : Window
{
public CustomCommandSample()
{
InitializeComponent();
}
private void ClearCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void ClearCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
txtEditor.Clear();
}
}
A static CustomCommands class:
public static class CustomCommands
{
public static RoutedUICommand Clear => new RoutedUICommand (
"Clear",
"Clear",
typeof(CustomCommands));
}
Finally the XAML:
(Note: the classes in this project are in namespace WpfCommandDemo. Xaml refers to it as Local)
<Window x:Class="WpfTutorialSamples.Commands.UsingCommandsSample"
xmlns="...
xmlns:local="clr-namespace:WpfCommandDemo"
Title="UsingCommandsSample" Height="100" Width="200">
<Window.CommandBindings>
<CommandBinding Command="CustomCommands.Clear"
CanExecute="ClearCommand_CanExecute"
Executed="ClearCommand_Executed" />
</Window.CommandBindings>
<DockPanel>
<WrapPanel DockPanel.Dock="Top" Margin="3">
<Button Command="CustomCommands.Clear"
CommandTarget="{Binding ElementName=txtEditor}"
Width="60">
Clear
</Button>
... (other buttons: cut / paste, as above
</WrapPanel>
<TextBox AcceptsReturn="True" Name="txtEditor" />
</DockPanel>
Although this compiles, The constructor of CustomCommandSample throws an XamlParseException:
Type reference cannot find type named
'{http://schemas.microsoft.com/winfx/2006/xaml/presentation}CustomCommands'.
Should I solve the problem using Custom Commands? What should I change? Or am I completely wrong, and should I solve this differently
To use CustomCommands in XAML, you'll need to add a reference to it. In the element, add a line:
xmlns:custom="clr-namespace:MyApplication.NamespaceWithCustomInIt"
Replacing the namespace value as appropriate. Then you should be able to reference CustomCommands anywhere in XAML as custom:CustomCommands (may have to bind, I'll check later).
Should I solve the problem using Custom Commands?
Yes. This is how to solve this using the Model-View-ViewModel (MVVM) design pattern which is the recommended design pattern to use when developing XAML based UI applications.
From this blog post:
WPF provides two implementations of the ICommand interface; the System.Windows.Input.RoutedCommand and System.Windows.Input.RoutedUICommand where the latter is a subclass of the former that simply adds a Text property that describes the command. However, neither of these implementations are especially suited to be used in a view model as they search the visual tree from the focused element and up for an element that has a matching System.Windows.Input.CommandBinding object in its CommandBindings collection and then executes the Execute delegate for this particular CommandBinding. Since the command logic should reside in the view model, you don’t want to setup a CommandBinding in the view in order to connect the command to a visual element. Instead, you can create your own command by creating a class that implements the ICommand. The below implementation is a common one that invokes delegates for the Execute and CanExecute methods:
public class DelegateCommand: System.Windows.Input.ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public DelegateCommand(Action<object> execute)
: this(execute, null) { }
public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null ? true : _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
Once you have an implementation of the ICommand interface, it's easy to use in your view models:
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
ClearCommand = new DelegateCommand(Clear);
}
private string _text;
public string Text
{
get { return _text; }
set { _text = value; NotifyPropertyChanged(); }
}
public ICommand ClearCommand { get; }
private void Clear(object parameter)
{
Text = string.Empty;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
In the view, you simply bind to the properties of the view model:
<TextBox AcceptsReturn="True" Name="txtEditor" Text="{Binding Text}" />
<Button Content="Clear" Command="{Binding ClearCommand}" />
Just remember to set the DataContext of the view to an instance of your view model for the bindings to work:
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
I need a "Remove" button for each item in the listbox of a UserControl. I am trying to use a ListBox Template.
<UserControl.Resources>
<DataTemplate x:Key="ListBoxItemTemplate">
<Grid>
<TextBlock x:Name="TB" Height="23" Text="" VerticalAlignment="Top" />
<Button Margin="500,0,0,0" Width="80" Click="Button_Click">remove</Button>
</Grid>
</DataTemplate>
</UserControl.Resources>
<ListBox x:Name="listbox" ItemTemplate="{StaticResource ListBoxItemTemplate}" SelectionChanged="ListBox_SelectionChanged"/>
How to make the text content of each item specified by the back-end code as shown below and how does the "remove" button remove its corresponding item?
Thanks.
listbox.Items.Add("111");
listbox.Items.Add("222");
Simpliest solution would be to use the ICommand system of WPF.
Using this, you can bind your current item to the commands parameter, and use that in code beind.
(I am using window, not user control, but you can just change that..
This is the WPF:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" x:Name="Window" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="ListBoxItemTemplate">
<Grid>
<TextBlock Height="23" Text="{Binding}" VerticalAlignment="Top" />
<Button Margin="500,0,0,0" Width="80" CommandParameter="{Binding}" Command="{Binding ElementName=Window, Path=OnClickCommand}">remove</Button>
</Grid>
</DataTemplate>
</Window.Resources>
<ListBox x:Name="listbox" ItemTemplate="{StaticResource ListBoxItemTemplate}" />
</Window>
{Binding} means to bind the current object the template is used on (in this instance, the string in my implementation.
The OnClickCommand is what does the magic.
C#:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
listbox.Items.Add("asdf");
listbox.Items.Add("fdsfsadf");
listbox.Items.Add("dfsd");
listbox.Items.Add("a sdfas");
listbox.Items.Add("asdgas g");
//This is the command that gets executed.
OnClickCommand = new ActionCommand(x => listbox.Items.Remove(x));
}
public ICommand OnClickCommand { get; set; }
}
//This implementation of ICommand executes an action.
public class ActionCommand : ICommand
{
private readonly Action<object> Action;
private readonly Predicate<object> Predicate;
public ActionCommand(Action<object> action) : this(action, x => true)
{
}
public ActionCommand(Action<object> action, Predicate<object> predicate)
{
Action = action;
Predicate = predicate;
}
public bool CanExecute(object parameter)
{
return Predicate(parameter);
}
public void Execute(object parameter)
{
Action(parameter);
}
//These lines are here to tie into WPF-s Can execute changed pipeline. Don't worry about it.
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
}
Note that it doesn't matter whether you use string or any other type of object, because {Binding} gets the current object that is in the ListBox.Items list
Time for my first question :)
I have the following:
public class BuilderViewModel : INotifyPropertyChanged
{
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private double _contentScale = 1.0;
public double ContentScale
{
get { return _contentScale; }
set
{
_contentScale = value;
NotifyPropertyChanged("ContentScale");
}
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#region Commands
bool CanZoomIn() { return true; }
void ZoomInExecute()
{
ContentScale += 1.0;
}
public ICommand ZoomIn { get { return new RelayCommand(ZoomInExecute, CanZoomIn); } }
#endregion
}
And the corresponding view:
<UserControl x:Class="PS_IDE.FormBuilder.View.Builder"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PS_IDE.FormBuilder.ViewModel">
<UserControl.DataContext>
<local:BuilderViewModel />
</UserControl.DataContext>
<TextBox Text="{Binding ContentScale}" Width="100" />
</UserControl>
I'm trying to have the ZoomIn command in BuilderViewModel update the text box value in it's view. The command is being fired from another user control, UIBuilder, which includes Builder. If I debug and fire the command from UIBuilder, I can see it updating ContentScale properly.
However, my text box value does not get updated (it only says "1", which is the initial value of ContentScale).
I know I'm missing something and hope someone can point me in the right direction.
EDIT: Added the control that is firing the command
<UserControl x:Class="PS_IDE.FormBuilder.UIBuilder"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PS_IDE.FormBuilder"
xmlns:ViewModel="clr-namespace:PS_IDE.FormBuilder.ViewModel"
xmlns:View="clr-namespace:PS_IDE.FormBuilder.View" mc:Ignorable="d">
<UserControl.DataContext>
<ViewModel:BuilderViewModel />
</UserControl.DataContext>
<DockPanel LastChildFill="True">
....
<ToolBarTray DockPanel.Dock="Bottom" HorizontalAlignment="Right">
<ToolBar>
<Button Height="24" Width="24" ToolTip="Zoom In" Command="{Binding ZoomIn}">
<Image Source="Images/ZoomIn.png" Height="16"/>
</Button>
....
</ToolBar>
</ToolBarTray>
<View:Builder x:Name="builder" />
</DockPanel>
</UserControl>
With the setting in both view:
<UserControl.DataContext>
<local:BuilderViewModel />
</UserControl.DataContext>
you are basically creating two viewmodels, one for each view. So when your Command updates the property it does it on one of the viewmodel but your textbox is bound to a different viewmodel.
To resolve it remove the DataContext setting from the Builder.xaml
Additionally you need to pass your DataContext to your Builder control (with this both view will share the same viewmodel).
So modify your UIBuilder.xaml:
<View:Builder x:Name="builder" DataContext="{Binding}" />
Use Mode TwoWay in your binding
Text ="{Binding ElementName=BuilderViewModel,
Path=ContentScale,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
Nota : use observable collection in order to send notify
I need to design a control that will capture the key stroke a user has pressed and treat that as the input.
I then need to display it to the user so they know which one they pressed.
I've tried using a textbox, and wiring up to the ValueChanged event, but it shows the key twice for some reason.
Does anyone know of a control that is already built that might handle this functionality?
Sidenote: I don't need an implementation with modifier keys or anything like that, I'm just trying to track a single key stroke for the time being.
Another way of looking at it is: In pretty much every PC video game, you can change the key bindings in the settings of the game. You go to the settings, find the key binding you're looking for, select it, and then hit a keystroke, then it captures that keystroke and changes the key binding to the keystroke the user entered.
That is exactly the functionality I'm looking for.
The simple way to do this would be data binding. In WPF this is quite easy. You can bind the data from one control to another. Below I have bound a TextBox, which has taken the user input, to a Label which displays it.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox Height="23" HorizontalAlignment="Left" Margin="45,55,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
<Label Content="{Binding ElementName=textBox1, Path=Text}" Height="28" HorizontalAlignment="Left" Margin="45,135,0,0" Name="label1" VerticalAlignment="Top" Width="142" />
</Grid>
The more complex answer would be to do Command binding. What this does is catches specific key bindings on a UserControl or Window and executes a given command. This is a little more complex because it requires you to create a class that implements ICommand.
More info here:
http://msdn.microsoft.com/en-us/library/system.windows.input.icommand.aspx
I personally am a big fan of the RelayCommand implementation by Josh Smith. There is a great article here.
In short though you can do this.
XAML:
<Window.InputBindings>
<KeyBinding Key="Escape" Command="{Binding KeyPressCommand}"/>
</Window.InputBindings>
CODE:
You will need to create a RelayCommand Class.
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
And then to implement this in your main window you will need to do this.
private RelayCommand _keyPressCommand;
public RelayCommand KeyPressCommand
{
get
{
if (_keyPressCommand== null)
{
_keyPressCommand = new RelayCommand(
KeyPressExecute,
CanKeyPress);
}
return _keyPressCommand;
}
}
private void KeyPressExecute(object p)
{
// HANDLE YOUR KEYPRESS HERE
}
private bool CanSaveZone(object parameter)
{
return true;
}
If you go with the second option I really suggest you take a look at the MSDN article by Josh Smith.
You have to catch the form event for this case,
Refer this Stack Overflow repeated question, it will provide you the answer
Fire Form KeyPress event
What I ended up having to do was this:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox Name="textBox1" PreviewKeyDown="previewKeyDown" />
</Grid>
and then in my even handler do this:
private void previewKeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
textBox1.Text = e.Key.ToString();
}
This basically disabled the default key functionality of the text box by setting
e.Handled = true
and then I changed the text of the textbox to be what I needed, which was the key that was pressed.
I'm using two views which refers same view model. Both of my views contain a text box that binds to a value in the view model. My problem is that, if I change the value of textbox in one GUI, its not reflecting in another. What should I do to achieve this?
This is my view model
public class ProductViewModel:INotifyPropertyChanged
{
private int machineheight;
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public int MachineHeight
{
get
{
return this.machineheight;
}
set
{
this.machineheight = value;
RaisePropertyChanged("MachineHeight");
}
}
public ProductViewModel()
{
}
private ICommand mUpdater;
public ICommand UpdateCommand
{
get
{
if (mUpdater == null)
mUpdater = new Updater();
return mUpdater;
}
set
{
mUpdater = value;
}
}
private class Updater : ICommand
{
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
SecondWindow w = new SecondWindow();
w.Show();
}
#endregion
}
}
}
The second window is another GUI. Once I click update button, second window opened. But the value that I have changed in first UI is not updated in the new window.
My Xaml is similar for both UI..
<Window x:Class="WPFDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFDemo"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:ProductViewModel/>
</Window.DataContext>
<Grid Height="307" Width="480" Initialized="Grid_Initialized">
<Button Content="Update" Height="32" HorizontalAlignment="Left" Margin="165,158,0,0" Name="button1" VerticalAlignment="Top" Width="114" Command="{Binding Path=UpdateCommand}"/>
<TextBox Height="42" HorizontalAlignment="Left" Margin="125,82,0,0" Name="textBox1" VerticalAlignment="Top" Width="169" Text= "{Binding Path= MachineHeight, Mode=TwoWay}" />
</Grid>
</Window>
I actually don't know what is the problem.. thanks
<Window.DataContext>
<local:ProductViewModel/>
</Window.DataContext>
hi, if you put this in your 2 views, then each one has its own viewmodel. so you will never see any changes. you have to set the datacontext from your first view to your second view. Btw for your ICommand implementation look at some mvvm frameworks for easier implementations, eg RelayCommand, DelegateCommand.
For your actual implementation you can add the following to your xaml and ViewModel(CommandParameter) then it works.
<Button Content="Update" Height="32" HorizontalAlignment="Left" Margin="165,158,0,0" Name="button1" VerticalAlignment="Top" Width="114" Command="{Binding Path=UpdateCommand}"
CommandParameter="{Binding .}"/>
public void Execute(object parameter)
{
SecondWindow w = new SecondWindow();
w.DataContext = parameter;
w.Show();
}
There are a hundred things that can go wrong in this scenario, and one of my long-standing gripes with XAML-based databinding is that the MS tools give you precious little help figuring out which of those hundred things it is. This is especially the case if you're new to databinding, but even folks who've been doing it for years can spend obnoxious hours tracking down databinding issues.
Some things to check:
(1) Confirm that your databindings are two-way.
(2) Look in your debug output window to see if there are any error messages there.
(3) Set an IValueConverter in your databinding, and set a breakpoint in the converter to see what data is being passed where and when.
(4) Confirm that the data in the ViewModel is actually being updated.
(5) Confirm that the ViewModel implements INotifyPropertyChanged, and that the PropertyChanged event is firing.
(6) Post your actual code here so folks can look at it.
And so forth.
Hope this helps.
It must work if the ViewModel implements INotifyPropertyChanged.