I want to create a special class of Command (I've called it DropDownRelayCommand, which are to be used on a dropdown button which has a content which consists of buttons with command.
The idea is that the dropdown button should be disabled (or possibly collapsed) if no buttons in it's content are enabled. I want to create a general solution.
I have been unable to do this in XAML (in a general way, anyway).
I want this DropDownRelayCommand to have it's own CanExecute methods, which should be examiing all CanExecute of its containing commands. The problem is this error (on the marked argument in the code below) : An object reference is required for the non-static field, method, or property 'Js.Mvvm.DropDownRelayCommand.CanDropDownExecute(T)'.
I cannot use "this" because that is not allowed in a constructor.
Here's my code (I am aware that the containing commands will propably be recieving canexecute request, making this a bit ineffective. But typically I would have only a handful commands so performance is propably not so important:
public class DropDownRelayCommand<T> : RelayCommand<T>
{
private readonly List<RelayCommand<T>> _commands = new List<RelayCommand<T>>();
private bool _hasAnyCanExecute;
#region Constructors
public DropDownRelayCommand(Action<T> execute, params RelayCommand<T>[] commands)
: base(execute, **CanDropDownExecute**)
{
AddCommandRange(commands);
}
public bool CanDropDownExecute(T argument)
{
_hasAnyCanExecute = false;
foreach (RelayCommand<T> command in _commands)
{
_hasAnyCanExecute = _hasAnyCanExecute || command.CanExecute(argument);
}
return _hasAnyCanExecute;
}
#endregion
#region Public Methods
public void AddCommandRange(params RelayCommand<T>[] commands)
{
if (commands == null) return;
foreach (RelayCommand<T> command in commands)
{
_commands.Add(command);
}
}
public void RemoveCommandRange(params RelayCommand<T>[] commands)
{
if (commands == null) return;
foreach (RelayCommand<T> command in commands)
{
if (_commands.Contains(command))
{
_commands.Remove(command);
}
}
}
#endregion
}
Related
I am currently trying to make a console for my game, and decided making a class called Command which can then be used to create commands easily was a good idea. I made the class but of course these classes are going to do vastly different thing, as such I was thinking of making a property which would basically act like a function, aka I could construct a command with properties commandName, arguments and then the customizable code block which would then be executed upon writing the command. How would I go about this?
public class Command : MonoBehaviour
{
string inputCommand;
int arguments;
void execution()
{
//this is where to codeblock to be executed upon typing the command would go
}
}
Edit:
I made what seems to be progress but still can't seem to get it right. Also each action needs to be able to have different amounts of arguments (for example "runes.add" needs an integer for runes to add and "updatestore" needs none). Any help would be greatly appreciated
public class Command : MonoBehaviour
{
public string InputCommand { get; set; }
public int Arguments { get; set; }
public Action ExecuteAction { get; set; }
}
public class Commands
{
public List<Command> commandCollection = new List<Command>()
{
new Command()
{
InputCommand = "",
Arguments = 1,
ExecuteAction = new Action(()=>{code to execute goes here})
}
};
}
First of all, you shouldn't derive Command from MonoBehaviour if you want to construct Command with object constructor (not Instantiate).
I think you should make abstract Command class and create commands as classes derived from Command class.
Also what you call "code block" can be done using polymorphism.
So, what you need to do:
Create Command class
public abstract class Command
{
public abstract void Execute(string[] args);
}
Execute method is abstract so we can override realisation of this method in subclasses. This methods takes an array of command arguments as the parameter.
Create some test commands
public class TestCommand : Command
{
public override void Execute(string[] args)
{
Debug.Log("Test command invoked, passed parameters count: " + args.Length);
}
}
Create CommandRegistry class (it's your Commands class)
public class CommandRegistry
{
private Dictionary<string, Command> _commands;
public CommandRegistry()
{
_commands = new Dictionary<string, Command>();
}
public void RegisterCommand(string name, Command command)
{
// You should also check here if command already exists
if(_commands.ContainsKey(name))
{
// Print error here or throw an exception
return;
}
_commands[name] = command;
}
public void RegisterAllCommands()
{
// Add here every new command to register it
RegisterCommand("test", new TestCommand());
}
// Returns false if command not found
public bool ExecuteCommand(string commandName, string[] args)
{
if(_commands.ContainsKey(commandName) == false)
return false;
_commands[commandName].Execute(args);
return true;
}
}
That's it. You need to call ExecuteCommand method to execute a command and pass a name and arguments of the command.
You should check argument count inside a Command.Execute method.
Also if you need to access your game methods/fields (for example to add runes) you should provide static access to this fields/methods or create something like CommandContext class (or GameContext).
An instance of this class will be passed to every command and it contains references to objects that can do things like adding runes.
Then you will need to add a new parameter (CommandContext) to GameRegistry.ExecuteCommand and Command.Execute method.
I wanted to implement a custom WPF command and I searched and found the following code:
public static class CustomCommands
{
public static readonly RoutedUICommand Exit = new RoutedUICommand
(
"Exit",
"Exit",
typeof(CustomCommands),
new InputGestureCollection()
{
new KeyGesture(Key.F4, ModifierKeys.Alt)
}
);
//Define more commands here, just like the one above
}
There are two things that I can't figure out.
Is it necessary to have commands static readonly? Cant we just declare it using const?
What exactly new InputGestureCollection() { new KeyGesture(Key.F4, ModifierKeys.Alt) } is? If it is calling default constructor and initializing properties so there should be a property to be assigned to, but there is nothing to be assigned. InputGestureCollection has braces, but inside braces it is not initialing any properties. How? What is this type of statement?
First of all, you need to get some basic understanding of WPF with MVVM.
You have a class that you are going to bind to your UI. That class is not the .xaml.cs
It is completely independent of the View. You need to put an instance of the class into the DataContext of the Window you can do this in the .xaml.cs by calling sth like that:
this.DataContext = new MyViewModel();
Now your class MyViewModel needs a Property of type ICommand.
Best practice is to make a class that implements ICommand. Normally you call it DelegateCommand or RelayCommand.
Example:
public class DelegateCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public event EventHandler CanExecuteChanged;
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)
{
if (_canExecute == null)
{
return true;
}
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
Then in your ViewModel you create a property with an Instance of that class in it. Like that:
public class MyViewModel{
public DelegateCommand AddFolderCommand { get; set; }
public MyViewModel(ExplorerViewModel explorer)
{
AddFolderCommand = new DelegateCommand(ExecuteAddFolderCommand, (x) => true);
}
public void ExecuteAddFolderCommand(object param)
{
MessageBox.Show("this will be executed on button click later");
}
}
In your view you can now bind the command of a button to that property.
<Button Content="MyTestButton" Command="{Binding AddFolderCommand}" />
A routed command is something that already exists in the framework by default (copy, paste etc). If you're a beginner to MVVM you shouldn't be thinking of creating routed commands before you get the basic understanding of "normal" commands.
To answer your first question: It is absolutely not nessesary to make Commands static and/or const. (See class MyViewModel)
Your 2nd question: You can initialize Lists with default values that you put into the {-brackets.
Example:
var Foo = new List<string>(){ "Asdf", "Asdf2"};
You don't have a object you initialize properties of. You have a list you initialize and then the Add() is called with the parameters you put in the {-brackets.
That's what basicly happens in your case too. You have a collection that you initialize with some values.
To answer your second question:
new InputGestureCollection()
{
new KeyGesture(Key.F4, ModifierKeys.Alt)
}
This is an example of a collection initializer and is equivalent to:
var collection = new InputGestureCollection();
collection.Add(new KeyGesture(Key.F4, ModifierKeys.Alt));
It's just a shorthand, and something that ReSharper suggests.
I have a static WindowService class which helps me to create new windows and modal dialogs.
So far, what I have is this:
/// <summary>
/// Opens a new window of type <paramref name="newWindowType"/> and closes the <paramref name="oldWindow"/>
/// </summary>
/// <param name="oldWindow">The window which should be closed (Usually the current open window)</param>
/// <param name="newWindowType">The type of the new window to open</param>
public static void ShowNewWindow(Window oldWindow, Type newWindowType)
{
((Window)Activator.CreateInstance(newWindowType)).Show();
oldWindow.Close();
}
My viewmodel raises an event and the view is subscribed to it. In the event handler in the view, it calls WindowService.ShowNewWindow(this,The type here). This works fine.
My modal dialog creating method will also work in a similar way. The only difference is that the information will be returned to the view (At the event handler) so the view will have to pass that information to the view model in code explicitly. This violates mvvm pattern and I don't know how to make the viewmodel wait for the view to return the value after the event is raised.
Is there a better way of doing this?
Ah, this ol' chestnut.
There are many different variations on how to achieve this, however here's my two cents.
The main ideas here are to ensure that your View and View Model do not know about each other, therefore your View should not subscribe to an event in your View Model, and your View Model should not directly call your service and provide a view Type.
Don't use events, use Commands instead
My recommendation would be to use ICommand implementations instead of relying on a static service class, for the reason that your class will always have a dependency to this service, and also as soon as you send the view Type to this service, then the MVVM pattern is lost.
So, firstly, we need some kind of command which will open a window of a given Type, here's what I have come up with:
public class OpenWindowCommand : ICommand
{
public bool CanExecute(object parameter)
{
TypeInfo p = (TypeInfo)parameter;
return p.BaseType == typeof(Window);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
if (parameter == null)
throw new ArgumentNullException("TargetWindowType");
//Get the type.
TypeInfo p = (TypeInfo)parameter;
Type t = p.BaseType;
if (p.BaseType != typeof(Window))
throw new InvalidOperationException("parameter is not a Window type");
//Create the window.
Window wnd = Activator.CreateInstance(t) as Window;
OpenWindow(wnd);
}
protected virtual void OpenWindow(Window wnd)
{
wnd.Show();
}
}
The class inherits from ICommand and specifies the implementation which accepts a Type, which represents the desired View that we want to open. Notice I have marked a method as virtual, I'll explain that part in a moment.
Here's how we can make use of this command in our View Model:
public class MainWindowViewModel
{
public OpenWindowCommand OpenWindowCommand { get; private set; }
public MainWindowViewModel()
{
OpenWindowCommand = new OpenWindowCommand();
}
...
}
Now we've created the command, we simply need to bind a Button to it:
<Button Content="Open Window"
Command="{Binding OpenWindowCommand}"
CommandParameter="{x:Type local:MyWindow}"/>
One thing to note here is that I am using x:Type as the CommandParameter, this is the Window that will be created when this command gets executed.
But what about a dialog?
What we achieved above is only half of the requirement, we now need something that will display a dialog and output the result to our View Model, this isn't so tricky as we have most of what we need already in our existing OpenWindowCommand.
First, we need to create the command:
public class ShowDialogCommand : OpenWindowCommand
{
private Action _PreOpenDialogAction;
private Action<bool?> _PostOpenDialogAction;
public ShowDialogCommand(Action<bool?> postDialogAction)
{
if (postDialogAction == null)
throw new ArgumentNullException("postDialogAction");
_PostOpenDialogAction = postDialogAction;
}
public ShowDialogCommand(Action<bool?> postDialogAction, Action preDialogAction)
: this(postDialogAction)
{
if (preDialogAction == null)
throw new ArgumentNullException("preDialogAction");
_PreOpenDialogAction = preDialogAction;
}
protected override void OpenWindow(System.Windows.Window wnd)
{
//If there is a pre dialog action then invoke that.
if (_PreOpenDialogAction != null)
_PreOpenDialogAction();
//Show the dialog
bool? result = wnd.ShowDialog();
//Invoke the post open dialog action.
_PostOpenDialogAction(result);
}
}
We're making use of our OpenWindowCommand by inheriting from it and using it's implementation instead of having to copy all of it into our new class. The command takes an Action which is a reference to a method in your View Model, you have the option of defining an action before or after (or both) a dialog is displayed.
The next step is to change our View Model so it creates this new command:
public class MainWindowViewModel
{
public OpenWindowCommand OpenWindowCommand { get; private set; }
public ShowDialogCommand ShowDialogCommand { get; private set; }
public MainWindowViewModel()
{
OpenWindowCommand = new OpenWindowCommand();
ShowDialogCommand = new ShowDialogCommand(PostOpenDialog);
}
public void PreOpenDialog()
{
throw new NotImplementedException();
}
public void PostOpenDialog(bool? dialogResult)
{
throw new NotImplementedException();
}
}
The usage of this command is practically the same as before, but it just references a different command:
<Button Content="Open Window"
Command="{Binding ShowDialogCommand}"
CommandParameter="{x:Type local:MyWindow}"/>
And there you have it, everything is loosely coupled, the only real dependencies here are that your View Model depends on your ICommand classes.
Some final words
The ICommand classes that I have created act as a controller between the View and the View Model to ensure that they do not know about each other, and keeps the MVVM pattern enforced.
Like I said at the beginning of this answer, there are many ways of which this can be achieved, however I hope you are now a little more enlightened.
The command object pattern is one that I still haven't been able to truly grasp and I found an implementation in the code I'm currently working on so I studied it long and hard to see if I could finally get it with a real world example. The problem is that I am sure this is not properly implemented and it is just an attempt by someone who just read about it and thought it made sense here.
Allow me to show it to you (for confidentiality reasons it will be greatly simplified but I'll do my best to show the main concepts):
public class CommandOne
{
public CommandOne(Manager manager, MyForm form)
{
m_manager = manager;
m_form = form;
}
public void Execute()
{
m_manager.CommandOne(m_form);
}
}
public class CommandTwo
{
public CommandTwo(Manager manager, MyForm form)
{
m_manager = manager;
m_form = form;
}
public void Execute()
{
m_manager.CommandTwo(m_form);
}
}
The first thing that strikes me as odd is that these two classes are not inheriting from any abstract class nor implementing a common interface.
The code that uses these commands is as follows:
public class MyForm : System.Windows.Forms.Form
{
public MyForm(Manager manager)
{
m_manager = manager;
}
private void SomeMethod()
{
....
var cmd = new CommandOne(manager, this);
cmd.Execute();
...
}
private void OtherMethod()
{
....
var cmd = new CommandTwo(manager, this);
cmd.Execute();
...
}
}
So the way I see it, this form is absolutely coupled to all the classes involved except the manager which is being injected to it through its constructors. So with this code I really don't see any benefit of creating the "command" classes which basically are just delegating the call to the manager's methods since the form is instantiating them when it needs them and calling the execute method right afterwards.
So could someone please explain what pieces, if any, is this implementation missing to truly be a command object pattern and, although it might be too subjective, what would be the benefit to implement it in this case?
Thank you.
Based on what you're showing here it looks like the benefit of the command pattern is lost. There are a few reasons you might want to use the command pattern in the context of a WinForms app.
You want to execute a command later
public interface ICommand
{
void Execute();
}
Keep a history of executed commands so they can be undone by the user
public interface ICommand
{
void Execute();
void Undo();
}
Check permissions to see if the current user has rights to execute the command. For example, maybe you have a RefundCustomerCommand and not all customer service agents have the right to issue a refund so you want to disable a button on the form.
public interface ICommand
{
void Execute();
bool CanExecute { get; }
}
You can also roll multiple commands together in a composite like this:
public class CompositeCommand : ICommand
{
private readonly List<ICommand> commands;
public CompositeCommand()
{
commands = new List<ICommand>();
}
public void Add(ICommand command)
{
commands.Add(command);
}
public void Execute()
{
foreach (var command in commands) command.Execute();
}
}
The command pattern also works nicely with the decorator. You can easily add additional cross-cutting behavior to your commands like retry logic:
public class RetryOnTimeout : ICommand
{
private readonly ICommand command;
private int numberOfRetries;
public RetryOnTimeout(ICommand command, int numberOfRetries)
{
this.command = command;
this.numberOfRetries = numberOfRetries;
}
public void Execute()
{
try
{
command.Execute();
}
catch (TimeoutException)
{
if (++numberOfRetries > 3)
throw;
Execute();
}
}
}
I have a closecommand defined inside my viewmodel for my dialog window. I have another command defined inside that viewmodel. Now I have that command binded to a control in my view. After performing certain command actions, I want it to call closecommand to close the window. Is that possible?
Yes. You can use a CompositeCommand that wraps both (or any number) of your other commands. I believe this is in Prism, but if you don't have access to that in your project, it isn't terribly difficult to implement similar functionality on your own, especially if you're not using parameters - all you do is implement ICommand with a class and then have a private List of ICommands inside the class.
Here's more on the CompositeCommand class from Prism:
http://msdn.microsoft.com/en-us/library/microsoft.practices.composite.presentation.commands.compositecommand_members.aspx
My own admittedly short and possibly non-canonical implementation follows. To use it, all you need to do is have this be referenced on your VM, and then bind to it instead. You can call .AddCommand for all the other commands that you want to run. Probably the Prism one is implemented differently, but I believe this will work:
public class CompositeCommand : ICommand {
private List<ICommand> subCommands;
public CompositeCommand()
{
subCommands = new List<ICommand>();
}
public bool CanExecute(object parameter)
{
foreach (ICommand command in subCommands)
{
if (!command.CanExecute(parameter))
{
return false;
}
}
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
foreach (ICommand command in subCommands)
{
command.Execute(parameter);
}
}
public void AddCommand(ICommand command)
{
if (command == null)
throw new ArgumentNullException("Yadayada, command is null. Don't pass null commands.");
subCommands.Add(command);
}
}