I'm currently toying a little with MVVM pattern and trying commands. I find the default way (every Command class needs to implement from ICommand interface) quite boring, so I've created a new base class called, wait for it, CommandBase. It looks like this:
public abstract class CommandBase : ICommand
{
public virtual bool CanExecute(object parameter)
{
return true;
}
public virtual event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public virtual void Execute(object parameter)
{
}
}
Now every command just inherits from this base class and overrides what is necessary. I had a bug in the software, so I've put several breakpoints in my inheriting class and in this base class. Everything seems to work as expected, except one thing - the method CanExecute gets fired all the time. If I put the breakpoint inside the method, my application won't even start! If I delete this breakpoint, everything works again.
MainViewModel:
public class MainViewModel : ViewModelBase // base implements INotifyPropertyChanged
{
public ICommand NavigateCommand { get; private set; }
public MainViewModel()
{
NavigateCommand = new NavigateCommand(this);
}
}
My debugger gets to the constructor, instantiate the Command class and from now on the method CanExecute fires like crazy and I can't even open the application window, because the vs debugger won't let me. In my NavigateCommand I only override Execute method and set one property of the MainViewModel, nothing too fancy. CanExecute is left intact without overriding.
Just a note, the bug I've mentioned was just a typo of my View, it wasn't related to this issue. After I've fixed it, code works except this thingy.
Can someone provide an explanation why it behaves like this?
It's a 'normal' behavior, that CanExecute gets fired often by the CommandManager. You shouldn't try to debug into this methods. In case of unknow bugs, turn on the Common Language Runtime Exceptions at Debug -> Exceptions... Further information here.
Can I suggest that, unless absolutely necessary, you don't need to reinvent the wheel here. There are a number of excellent implementations of ICommand out there that you can use.
RelayCommand is probably the most commonly used, although DelegateCommand is also very well implemented, and is the standard ICommand implementation is the Prism framework.
Related
This may be an X-Y problem. Please don't hesitate to tell me if I'm completely off-base here.
First, a simplified example of the kind of situation I am thinking of.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace XXXXXXX
{
public class AbstractOperation : INotifyPropertyChanged
{
public enum OpState { Init, Running, Aborted, Completed, Errored };
OpState privateOperationState;
public OpState OperationState
{
get => privateOperationState;
private set
{
if(privateOperationState!=value)
{
privateOperationState = value;
OnPropertyChanged();
}
}
}
public bool IsRunning => OperationState == OpState.Running;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
public class BackgroundOperator
{
AbstractOperation whatever;
public bool IsRunning => whatever.IsRunning;
public AbstractOperation.OpState OperationState => whatever.OperationState;
}
}
AbstractOperation is to be a base class representing some multi-step operation that takes significant time to perform. It will expose the status of it's operation through some properties.
BackgroundOperation is a class that will take an AbstractOperation and run it in a background thread, passing through some of the status properties. I want to be able to bind some UI element properties to these operations so that, for example, a certain control is disabled while the operation is running. I understand that the INotifyPropertyChanged interface is necessary for bindings like this to work.
If I implement the PropertyChange event on just one property like this, will the notification automatically cover other properties that refer to this property in their body? Does it work only within the class, or does it still work with another class that owns an instance of the notifying class? Do I need to do some special code to link the referring properties to the original property's notification? Or am I deep into X-Y land here and should implement some other way of binding UI controls to the status of my operation?
If I implement the PropertyChange event on just one property like this, will the notification automatically cover other properties that refer to this property in their body?
What happened when you tried it? Did you get property change notification for other properties?
Does it work only within the class, or does it still work with another class that owns an instance of the notifying class?
It doesn't do that at all, so it won't do it in any other class.
Property change notification isn't magic. It just raises the event, setting the name value in the event args object to the one you passed in to the OnPropertyChanged() method (in this case, implicitly via the [CallerMemberName] attribute).
All that said, using properties like this isn't necessarily the best way to deal with disabling commands. You don't say what API you're actually using, but a common one that uses this sort of pattern is WPF. It uses ICommand bindings for commands. The ICommand.CanExecute() method should be used to indicate whether a command is valid at a given time. ICommand.CanExecuteChanged should be raised when the value for that method changes. This is typically done by whatever code begins an operation or changes some state that would render the command invalid at that time. The same code would then change the CanExecute() state back to valid when it's done.
The exact mechanism for changing the command state and raising its event depends on how you implement the command. There are lots of examples out there, which you should review. See what works best for you.
If you are using some other API, it may or may not have a similar mechanism. It's not possible to know what the best answer along those lines would be, since that information is not available in your question.
I am currently working on a project that is requiring drag and drop functionality.
I am using the GongSolutions.DragDrop nuget package in order to simplify my solution. The library allows you to bind a "dd:DragDrop.DropHandler" attribute on the xaml to a class that implements the IDropTarget interface.
Inside my viewmodel I have created an inner class to implement this and have bounded to it as such, the functionality works but for some reason I am unable to hit any breakpoints within this inner class? I was able to hit all breakpoints when I had the viewmodel itself inherit from it but I decided to implement an innner class so I can have multiple drophandlers within it.
The following is the code with details removed for simplicity as there is a lot of code, breakpoints work inside the MainViewModel but when you set a breakpoint within ModuleItemsListDropHandler it will not hit the breakpoint at all
public class MainViewModel
{
ObservableCollection<ModuleItem> _moduleItems;
public ObservableCollection<ModuleItem> ModuleItems
{
get { return _moduleItems; }
}
ObservableCollection<ModuleItem> _moduleTiles;
public ObservableCollection<ModuleItem> ModuleTiles
{
get { return _moduleTiles; }
}
//breakpoints work within this method
public void addToList(MouseEventArgs e)
{
//removed for simplicity
}
public MainViewModel()
{
//removed for simplicity
}
//Class that will not let me hit breakpoints that are set
class ModuleItemsListDropHandler : IDropTarget
{
void IDropTarget.DragOver(IDropInfo dropInfo)
{
//functionality during drag over
}
void IDropTarget.Drop(IDropInfo dropInfo)
{
//functionality for drop
}
}
}
I am currently using the community edition of VS 2015
It's very unlikely that you have a class that just doesn't work with the debugger. Best bet is that the method isn't really being called. A quick call to System.Diagnostics.Trace.WriteLine() or even MessageBox.Show() can answer that question without much trouble.
However. Is this really how your drop handler class is defined?
public class MainViewModel
{
...
class ModuleItemsListDropHandler : IDropTarget
{
If so, that's a private class, so I wonder how you're binding an instance of it to anything in the XAML. You can't declare a non-private property with that return type, for example. You could be returning it as IDropTarget or as Object from something, of course.
Incidentally, classes (or anything defined directly in a namespace) ordinarily default to internal access, not private, but a child class, like a class member, defaults to private.
I'm not an absolute beginner, but this one is seemingly beyond me (or maybe I'm out of energy at the end of the day here :)). What is the following code piece trying to achieve (taken from this SO post)?
public class ObservableStack<T> : Stack<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
//...
protected virtual event PropertyChangedEventHandler PropertyChanged;
//...
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
add { this.PropertyChanged += value; }
remove { this.PropertyChanged -= value; }
}
}
I need to translate this to VB.NET, which doesn't seem to be happy with the existence of two PropertyChanged events. Which one needs to be removed while still implementing the interface correctly?
There are two ways to do this in VB. First, and easiest, is to get rid of the explicit implementation of INotifyPropertyChanged. Make the protected event public, and don't use the explicit one with the add/remove blocks.
However, it happens that ObservableCollection<T> implements INotifyPropertyChanged explicitly itself, so there may be some good reason to do that. Ordinarily I do whatever the framework does, because historically their ideas are, on average, better than mine. In this case I don't know why they did it that way, but at the very worst it can't hurt.
And it turns out you can implement interfaces explicitly in VB.NET. In theory. But I tried doing something based on this Lovecraftian example code here, and gave up in horror and despair.
I think you'll be fine just implementing the interface regularly.
Given a basic C# library, how do I implement functions of this library into my WPF application to handle appropriately the concepts of Binding and Commands?
I mean, need I write some own wrappers for these library classes in order to implement interfaces such as ICommand or should this be done directly in the library itself?
Some code to get my question more comprehensible:
From the library:
public class Item
{
public string Name { get; set; }
public void DoSomething() { throw new NotImplementedException; }
}
I want to implement the function DoSomething() in my XAML markup without any line of code in that .cs file since that is, from what I've read, the best practice.
(Assuming that an instance of Item is bound to the control)
<Button Command="{Binding DoSomething}"/>
Well, in order to do so, I need to implement the interface ICommand and create a command, but that is, as stated above, unclear to me since I'm using a library here.
Should I write my own Wrapper for the Item class of the API and implement the ICommand interface or is there any other way to archieve this? I've written the library by myself so changes are possible. I'm just not entirely sure about changing the library because if I do so, it is (possibly) bound to WPF.
Hi there if anything your ViewModel should handle any requests on your Model that's it's sole purpose, to get these things to work you need ICommand and if you want some more info here is link with a tutorial on RoutedCommands. If you have your Model and ViewModel defined then you can easily assign tasks to the particular Model through its VM.
P.S. I think you could treat your library as a Model and write a "wrapper" ViewModel to handle operations on it. HTH
UPDATE
Consider following:
class libClass
{
void method()
{
//do something here
}
}
code above would be your model and if you want it to be more readable you could do it this way
class libModel
{
private libClass _libClass;
public libClass LibClass { get; set; }
}
Note
You could implement INotfiyPropertyChanged in your Model to handle any changes if needed of course.
now in your VM how you use the Model
class ViewModel
{
private libModel _libModel;
public libModel LibModel { get; set; }
//after you set up your RoutedCommands
//I declare method within my VM to handle the RoutedCommands don't know
//if it works when you use Property Method
void VMMethod()
{
//use VM's property to invoke desired method from your lib
}
}
and voila! ready "wrapper" for your class with implementation in your VM.
Tip
If you want to know how to do the RoutedCommands here is a link to a tutorial.
I'm just starting out with WPF and I want to use custom commands whenever possible as part of the MVVM pattern. The book that I've been using (C# 2010 All-in-One for Dummies) has a sample of a custom command but it uses hard coded information to complete its task and I don't see how to use the Command system to complete my task.
Book Code:
public abstract class CommandBase : ICommand
{
public string Text { get; internal set; }
public abstract void Execute(object parameter);
public abstract bool CanExecute(object parameter);
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
public class AddCustomerCommand : CommandBase
{
public AddCustomerCommand()
{
Text = “Add Customer”;
}
public override void Execute(object parameter)
{
var list = parameter as IList<Customer>;
if (list == null)
{
return;
}
list.Add(new Customer { ID = 4, Name = “New Customer”} );
}
public override bool CanExecute(object parameter)
{
return parameter is IList<Customer>;
}
}
In this case, Execute works because it is passed an IList<Customer> and can add to it without needing to return anything. This makes perfect sense to me.
My Problem:
I have an MVVM app that has a data grid, some text boxes, and some buttons. My view model has IList<Entry> Entries, properties for the text boxes, and of course an instance of my custom command AddEntryCommand. The goal is to be able to enter text, and hit add, and have a new Entry be added to Entries using AddEntryCommand.
What I don't understand is how to go about getting Entries and the new data into the command. Here are the possible solutions I've thought of and what I see wrong with them
Pass in the view model so that all its information is available.
Pass in an array of objects.
Pass in a Tuple.
Passing thew view model seems excessive, and if I do that then everything on the view model would have to be mutable.
I try and avoid using object whenever possible, and object[] seems even more work to deal with. I'd have to pick it apart like command line arguments.
Tuples...
My idea of a command is that it's supposed to be a method with bells and whistles for making the UI react nicely. Anything that causes the command to be tied to a specific view or view model breaks that.
So my questions are:
How do you do work with multiple objects using ICommand?
How can you use ICommand to work with immutable objects if it's locked to return void?
Is my idea of what a command is for way off base?
(I've tried searching for a better tutorial or resource for this but my Google fu is weak and I can't seem to locate anything that's clear and concise. There are lots of questions on SO about commands in WPF, but they're all for very specific implementations. I'm looking for a general answer regarding manipulating multiple objects in one command.)
UPDATE
I have been looking around the net some more but I still haven't found anything like the sample provided by my book. I have looked at DelegateCommand and that seems like a pretty straightforward and easy to use system. It still leaves me wondering why such a large chunk of the chapter on MVVM would be dedicated to creating a custom command using just ICommand and not one of the other classes that already inherit from it.