I've been trying to find a nice neat and succinct way to declare RelayCommands in my ViewModels.
The best I can come up with is:
public class MyViewModel
{
public ICommand StopCommand { get; private set; }
public MyViewModel()
{
StopCommand = new RelayCommand(OnStop);
}
private OnStop(object sender)
{
//hammertime
}
}
What I'd really like to do it remove the two stage declaration/construction, something like:
public class MyViewModel
{
public readonly ICommand StopCommand = new RelayCommand(OnStop);
private OnStop(object sender)
{
//hammertime
}
}
However, this fails to compile with
error CS0236: A field initializer cannot reference the non-static
field, method, or property 'MyViewModel.OnStop(object)'
It there a neater / "standard" way that people use?
I've used the first format you specified quite a bit and it works fine for me.
Also - if you're using WPF, binding doesn't work with fields anyway so even if you can get the second approach to compile, it won't hook up to your UI.
One option is to abandon commanding which has it's limitations, and use another mechanism such as Actions provided by Caliburn.Micro. Then, you just need your view model verb:
public void Save()
{
}
<Button x:Name="Save">Save</Button>
I was using something like:
public ICommand StopCommand
{
get{return new RelayCommand(OnStop);}
}
Related
I am implementing a WPF application and I am switching view models on button click. I had to implement an navigation store by youtube tutorial. When I click a button, navigateCommand will execute, creating a new viewModel and notifying view to change. However I dont understand what is method OnCurrentViewModelChanged() doing and why is it needed, action CurrentViewModelChanged is returning void, and is empty? Or am I missing something? What is CurrentViewModelChanged doing? Can someone please explain?
public class NavigationStore
{
public event Action CurrentViewModelChanged;
private NotifyPropertyChanged currentViewModel;
public NotifyPropertyChanged CurrentViewModel
{
get => currentViewModel;
set
{
currentViewModel = value;
OnCurrentViewModelChanged();
}
}
private void OnCurrentViewModelChanged()
{
CurrentViewModelChanged?.Invoke();
}
}
public class NavigateCommand<TViewModel> : CommandBase where TViewModel : NotifyPropertyChanged
{
private readonly NavigationStore _navigationStore;
private readonly Func<TViewModel> _createViewModel;
public NavigateCommand(NavigationStore navigationStore, Func<TViewModel> createViewModel)
{
_navigationStore = navigationStore;
_createViewModel = createViewModel;
}
public override void Execute()
{
_navigationStore.CurrentViewModel = _createViewModel();
}
}
public class MainViewModel : NotifyPropertyChanged
{
private readonly NavigationStore _navigationStore;
public NotifyPropertyChanged CurrentViewModel => _navigationStore.CurrentViewModel;
public MainViewModel(NavigationStore navigationStore)
{
_navigationStore = navigationStore;
_navigationStore.CurrentViewModelChanged += OnCurrentViewModelChanged;
}
private void OnCurrentViewModelChanged()
{
OnPropertyChanged(nameof(CurrentViewModel));
}
}
So first of all, I also followed his tutorials (it's most likely SingletonSean's) and I don't share #BenicCode's opinion on that (tho I'm not a professional at WPF like he may be), I really like his explanations and solutions to problems. Besides, he keeps changing the project throughout the guide, implementing better solutions and explaining why it's better to use this than that.
The OnCurrentViewModelChanged() method raises an event so that any method that is subscribed to it will be invoked. However, you actually don't need it, you can implement NavigationStore like this:
NavigationStore.cs
public class NavigationStore : INavigationStore
{
private ViewModelBase? _currentViewModel;
public ViewModelBase? CurrentViewModel
{
get => _currentViewModel;
set
{
_currentViewModel?.Dispose();
_currentViewModel = value;
NavigationStateChanged?.Invoke();
}
}
public event Action? NavigationStateChanged;
}
And now, in your MainViewModel, you can simply subscribe the NavigationStateChanged action to OnCurrentViewModelChanged() instead of having one more method in your navigation store.
MainViewModel.cs
public class MainViewModel : ViewModelBase
{
private readonly INavigationStore _navigationStore;
public ViewModelBase? CurrentViewModel => _navigationStore.CurrentViewModel;
public MainViewModel(INavigationStore navigationStore)
{
_navigationStore = navigationStore;
_navigationStore.NavigationStateChanged += OnNavigator_NavigationStateChanged;
}
private void OnNavigator_NavigationStateChanged()
{
OnPropertyChanged(nameof(CurrentViewModel));
}
}
It's basically the same, but a bit simpler (correct me if I'm wrong). By subscribing NavigationStateChanged to OnNavigator_NavigationStateChanged, whenever NavigationStateChanged is raised, OnNavigator_NavigationStateChanged will fire too, which will notify your UI to change (since you bind the ContentControl's Content property to the CurrentViewModel property).
MainWindow.xaml
<Grid>
<ContentControl Content="{Binding CurrentViewModel}" />
</Grid>
At this point of the tutorial he just wanted to demonstrate really basic navigation. As you progress further, things get cleaner and more complicated. I really suggest finishing his tutorials, there might be better guides, but as a starting point, I couldn't find any better channel.
I was primarily following this tutorial: http://www.codeproject.com/Articles/238657/How-to-use-Commands-in-WPF
But then I realize the RelayCommand is part of another framework that I can't use. This is the code I have:
public ICommand TestCommand
{
get;
internal set;
}
private bool CanExecuteTestCommand()
{
return !string.IsNullOrEmpty(txtUsername);
}
private void CreateTestCommand()
{
TestCommand = new TestCommand(TestExecute, CanExecuteTestCommand);
}
public void TestExecute(object parameter)
{
obj.TestConnection();
}
And the XAML:
<Button Content="Test Connection" Command="{Binding Path=TestConCmd}" />
But this won't compile because TestCommand is, obviously, an invalid type.
I've looked over this tutorial as well:
http://www.codeproject.com/Articles/274982/Commands-in-MVVM
But similarly, Command doesn't seem to be a type even though I've added using System.Windows.Input.
Then all the other tutorials I've looked at just use built-in commands like closing the application, pasting from the clipboard and a few other things like that.
So... How do I actually create my command?
Command is not a type, ICommand is. You must derive from/implement it:
public class TestCommand : ICommand
{
public override void Execute(object parameter)
{
//Do stuff
}
}
And subsequently implement the methods, especially Execute(object parameter). Then you can do:
TestCommand = new TestCommand();
in your View Model as before. Of course, you can re-implement RelayCommand or something like it. Is Josh Smith's implementation of the RelayCommand flawed? Shows some code and easy to make mistakes.
I want main viewmodel to have a certain list, and then access from many other viewmodels.
For example, in MainViewModel.cs I will have a list of 50 numbers,
then in NumListViewModel.cs, I'd like to access it in order to show it as a list, and in AddNumViewModel.cs I'd like to be able to update that list.
It's been suggested that I use events / evenaggerator, which I did, but unfortunately, for all I know all I can do with it is send a num from one view to another and tell it to update the list, but the problem is, as the program grows, I will need to have a lot of subscribers in the main view model, and when something actually happens I will have to "publish" events according to the number of subscribers which makes it even harder to maintain.
I also found another answer, instructing to create an instance of anotherVM within the mainVM, with a parameter set to "this" which is a reference to the mainVM.
It works, but then again, it could get quite long.
So my question is, is there a better way to access a property from another VM?
Like literally have the an instance of the class that holds the list in the mainVM, and then just be able to update / access it from the other VMs, without having to explicitly program which VM can. Would make life so much easier.
In your answer, please try to avoid suggesting frameworks.
Although there are some really good ones, I want to be able to do at least that by myself.
For example:
MainVM.cs:
public class MainVM
{
List lst = new List(); //Let's just say it's full...
}
OtherVM.cs:
public class OtherVM
{
lst.Add(3);
}
PS: Yes I know it has been asked already, and yes I have done my research, BUT I the answers I found are too 'static', I guess?
If you want direct access to the list from an external ViewModel, then your options are to:
Pass the List to the OtherVM as a constructor argument or public property. Then the OtherVM can treat it like a member.
Pass the MainVM to the OtherVM as a constructor argument or public property. Then the OtherVM can access the List by first accessing the MainVM.
Example:
public class MainVM
{
public List<XX> MyList { get; set; }
}
public class OtherVM
{
public MainVM TheMainVM { get; set; }
public OtherVM(MainVM theMainVM)
{
TheMainVM = theMainVM;
// Access the MainVM's list
TheMainVM.MyList.Add(stuff);
}
}
Give the MainVM a static property called "Default" or "Instance," so you can access the static instance of MainVM from within OtherVM, without assigning it as a member field.
Example:
public class MainVM
{
private static MainVM _instance = new MainVM();
public static MainVM Instance { get { return _instance; } }
public List<XX> MyList { get; set; }
//other stuff here
}
//From within OtherVM:
MainVM.Instance.MyList.Add(stuff);
Most of the WPF mvvm applications, we are using ICommand in the view-model. But it is referring to System.Windows.Input. so the view-model is now tightly couple with System.Windows.Input namespace. according to my understanding view-model should be able to use in normal C# winform application or asp.net application.
Normally we are using following code lines to the command with RelayCommand implementation.
private RelayCommand testCommand;// or private ICommand testCommand;
public ICommand TestCommand
{
get
{
return testCommand ??
(testCommand = new RelayCommand(param => Test()));
}
}
public void Test()
{
}
What i feel is we need to remove all the ICommand and use RelayCommand instead. So we can eliminate the System.Windows namespace from the view-model. so final code will looks like this,
private RelayCommand testCommand;
public RelayCommand TestCommand
{
get
{
return testCommand ??
(testCommand = new RelayCommand(param => Test()));
}
}
public void Test()
{
}
Any suggestions on this approach? or is there any way to eliminate the System.Windows namespace from the view-model?
Any suggestions on this approach?
This still doesn't decouple you from System.Windows.Input as RelayCommand still must implement ICommand, even if it's indirectly implementing it.
Implementing ICommand within the ViewModel is one of those things that tends to be required in order to be pragmatic. Ideally, ICommand (or a similar interface) would have been implemented in a namespace that wasn't XAML specific. That being said, it is supported directly within the Portable Class Libraries, so it is not tied to a specific framework (WPF, Silverlight, Phone, etc) as much as XAML in general.
Pretty simple to avoid coupling your ViewModel to ICommand, if you want to. Probably not a bad idea, WPF will probably go the way of MFC one day. Overkill? maybe, but here is a how:
In your view:
<StackPanel>
<Button Command="{Binding Path=MyCommand}"> Do it! Kill me Now!</Button>
<TextBlock Text="{Binding Path=Message}"></TextBlock>
</StackPanel>
Inject your ViewModel into your DataContext, Take the responsibility for the native commands, out of your view model:
public class ViewModel : INotifyPropertyChanged
{
public string Message { get; set; }
public object MyCommand { get; set; }
public void OnMyCommand(object parameter)
{
Message += "I Ran something" + Environment.NewLine;
}
public bool CanMyCommand(object parameter)
{
return true;
}
// Injected Native Command handler
public ViewModel(ICommandFactory factory)
{
MyCommand = factory.CreateInstance(OnMyCommand, CanMyCommand);
}
public event PropertyChangedEventHandler PropertyChanged;
}
Note I'm using FODY to weave in the property change handler. INotifyPropertyChanged is System.dll btw.
Now, Bind this contract:
public interface ICommandFactory
{
object CreateInstance(Action<object> action, Func<object, bool> predicate);
}
... to something that will give you a native Command object;
public class NativeCommand : ICommand
{
private readonly Action<object> _action;
private readonly Func<object, bool> _predicate;
public NativeCommand(Action<object> action, Func<object, bool> predicate)
{
_action = action;
_predicate = predicate;
}
public bool CanExecute(object parameter)
{
return _predicate(parameter);
}
public void Execute(object parameter)
{
_action(parameter);
}
public event EventHandler CanExecuteChanged;
}
public class NativeCommandFactory : ICommandFactory
{
public object CreateInstance(Action<object> action, Func<object, bool> predicate)
{
return new NativeCommand(action, predicate);
}
}
Bind<ICommandFactory>().To<NativeCommandFactory>();
VoilĂ , decoupled commands.
Also note, your injection is done at initial application start. Your ViewModel is decoupled from whatever IoC container you choose.
Well, in theory, you are pretty much right. It would if nice of ICommand was completely UI-platform-independent.
But from a practical standpoint, if you are using MVVM in a WPF app, there's a pretty good chance you are fairly dependent on WPF's databinding and datatemplating capabilities anyway. Trying to stick a WinForms UI on top of something like that would likely require a significant amount of extra effort.
I've worked on some fairly large WPF/MVVM projects in the past. We considered MVVM to be a way of separating the specific details of the UI from the code - not so that we could switch to WinForms/ASP.NET/whatever, but so that we could change the look and feel of our UI (i.e. edit the XAML) without having to change the ViewModels. In this respect, MVVM worked perfectly.
If you are really concerned about sharing code across multiple types of projects, it might be better to try and put your common code in a typical 'Business Layer'-type class library, instead of in view model.
I've seen a lot of example code written using something like (please forgive how horribly canned this is):
public class Test
{
public object Thingy { get; private set; }
}
Unfortunately, these kinds of examples never really explain why 'set' is set as private. So, I'm just wondering if there's a good, common example that will illustrate to me why something like this would be used.
I sort of see it - the property can be run to process some extra logic in addition to setting that field. I'm just confused on how it would be invoked, and why this approach would be used rather than a generic setter method.
This would be if you have a property that you don't want anyone to set but your class. This can be handy with database id's. The internal class can set it but you wouldn't want anyone else changing it. So you can give them read access but not write.
EDIT: One more point on this is that using what you showed there is helpful for automatic properties. Unfortunately with automatic properties you are unable to only specify get so to avoid exposing a setter publicly it is just made private.
EDIT: Just thought I would throw in an example. Automatic properties are great for clean, terse code. But like you showed there is a limitation in that you have to have get and set. So before it was like this for a property like you showed:
public class Test
{
private object thingy;
public object Thingy
{
get { return thingy; }
}
}
Now we can get rid of that unneeded private declaration but it requires both. So make private to get around that.
I know this was overkill on the explanation but different things kept popping in my head.
As a simple example; it is a cheap way of making an "immutable enough" object (for use in threading, state, etc). But also anywhere where the client simply shouldn't need to assign it, or can't be trusted to assign it (correctly).
Another example might be a list:
public List<Foo> Items {get;private set;}
since we might call obj.Items.Add() etc, but we would rarely assign obj.Items = .... However, this example is marred by needing explicit initialization in the constructor, and XmlSerializer hates it - to be honest for lists I mainly use:
private readonly List<Foo> items = new List<Foo>();
public List<Foo> Items {get { return items;}}
which solves both of these.
As another example, contrasting:
private readonly int foo;
public int Foo {get{return foo;}}
vs
private readonly int foo;
public int Foo {get{return foo;} private set {foo=value;}}
this pattern may be useful in serialization, for example with DataContractSerializer (with the addition of some attributes), since many serializers will still look for private accessors. This avoids us having to decorate our internal state (foo), but gives the veneer of privacy to the set.
Ultimately anything can be bypasses and assigned via reflection, so private set is only intended to avoid accidental damage to data.
The private makes it into a readonly property. A common example is if you have multiple classes passing around a single object, you don't want another class to be able to modify the instance.
Basically, it is a readonly property. If it was written in full (not as an auto property) you would simply leave out the setter.
Two examples that are largely the same:
class Foo1
{
public int Id { get; private set; }
public Foo1()
{
Id = lastId ++;
}
}
class Foo2
{
private int _id;
public int Id { get { return _id; } }
public Foo2()
{
_id = lastId ++;
}
}
I've seen this used with the design:
public class whatever
{
public string WhateverId { get; private set; }
public static whatever Create(string whateverId)
{
return new whatever() { WhateverId = whateverId };
}
}
So you create whatever class, but after it's created the id can't be changed because it might break things that are connected to it.
the private set just gives the simple initializer syntax, I kind of like it for some scenarios.
Also can be used if it's changeable, but you need to manage it when changes are made
public void SetWhateverId(string whateverId)
{
DisconnectAllCurrentWhateverIdReferences();
WhateverId = whateverId;
ReconnectAllPreviousWhateverIdReferences();
}
This syntax allows you to provide a public-facing property that appears read-only to consumers of your API but internally can be changing. By auto-implementing in this way, you avoid having to write boilerplate code such as a distinct setter or a backing field for the value, and you leave room in your design to add a bespoke set algorithm if it is deemed necessary at some point in the future without having to decide right away.
private set is very handy for simple immutable value types.
struct Point
{
public int X { get; private set; }
public int Y { get; private set; }
public Point(int x, int y)
{
this = default(Point);
X = x;
Y = y;
}
}
This is just laziness that comes about from auto-properties. Before auto properties were around, people would implement the getter and omit the setter for properties which are meant to be read-only.
public class Test
{
private /*readonly*/ Type _thingy;
public Type Thingy { get { return _thingy; } }
}
Hopefully, C# 5 will allow you to create auto-properties with a getter only - because that's what everyone wants. (They should make readonly setters in auto-props too, I need that badly)
To answer the question of a common scenario where this might be used...
In an MVP pattern, if your Model exposes some properties for your Presenter I would write
public string Bazinga { get; private set; }
Now, the Model can change this value but other classes that use it cannot.