Implementing MVVM in WPF without using System.Windows.Input.ICommand - wpf

I'm trying to implement a WPF application using MVVM (Model-View-ViewModel) pattern and I'd like to have the View part in a separate assembly (an EXE) from the Model and ViewModel parts (a DLL).
The twist here is to keep the Model/ViewModel assembly clear of any WPF dependency. The reason for this is I'd like to reuse it from executables with different (non-WPF) UI techs, for example WinForms or GTK# under Mono.
By default, this can't be done, because ViewModel exposes one or more ICommands. But the ICommand type is defined in the System.Windows.Input namespace, which belongs to the WPF!
So, is there a way to satisfy the WPF binding mechanism without using ICommand?
Thanks!

You should be able to define a single WPF custom routed command in your wpf layer and a single command handler class. All your WPF classes can bind to this one command with appropriate parameters.
The handler class can then translate the command to your own custom command interface that you define yourself in your ViewModel layer and is independent of WPF.
The simplest example would be a wrapper to a void delegate with an Execute method.
All you different GUI layers simply need to translate from their native command types to your custom command types in one location.

WinForms doesn't have the rich data binding and commands infrastructure needed to use a MVVM style view model.
Just like you can't reuse a web application MVC controllers in a client application (at least not without creating mountains of wrappers and adapters that in the end just make it harder to write and debug code without providing any value to the customer) you can't reuse a WPF MVVM in a WinForms application.
I haven't used GTK# on a real project so I have no idea what it can or can't do but I suspect MVVM isn't the optimal approach for GTK# anyway.
Try to move as much of the behavior of the application into the model, have a view model that only exposes data from the model and calls into the model based on commands with no logic in the view model.
Then for WinForms just remove the view model and call the model from the UI directly, or create another intermediate layer that is based on WinForms more limited data binding support.
Repeat for GTK# or write MVC controllers and views to give the model a web front-end.
Don't try to force one technology into a usage pattern that is optimized for another, don't write your own commands infrastructure from scratch (I've done it before, not my most productive choice), use the best tools for each technology.

Sorry Dave but I didn't like your solution very much. Firstly you have to code the plumbing for each command manually in code, then you have to configure the CommandRouter to know about each view/viewmodel association in the application.
I took a different approach.
I have an Mvvm utility assembly (which has no WPF dependencies) and which I use in my viewmodel. In that assembly I declare a custom ICommand interface, and a DelegateCommand class that implements that interface.
namespace CommonUtil.Mvvm
{
using System;
public interface ICommand
{
void Execute(object parameter);
bool CanExecute(object parameter);
event EventHandler CanExecuteChanged;
}
public class DelegateCommand : ICommand
{
public DelegateCommand(Action<object> execute) : this(execute, null)
{
}
public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public void Execute(object parameter)
{
_execute(parameter);
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public event EventHandler CanExecuteChanged;
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
}
}
I also have a Wpf library assembly (which does reference the System WPF libraries), which I reference from my WPF UI project. In that assembly I declare a CommandWrapper class which has the standard System.Windows.Input.ICommand interface. CommandWrapper is constructed using an instance of my custom ICommand and simply delegates Execute, CanExecute and CanExecuteChanged directly to my custom ICommand type.
namespace WpfUtil
{
using System;
using System.Windows.Input;
public class CommandWrapper : ICommand
{
// Public.
public CommandWrapper(CommonUtil.Mvvm.ICommand source)
{
_source = source;
_source.CanExecuteChanged += OnSource_CanExecuteChanged;
CommandManager.RequerySuggested += OnCommandManager_RequerySuggested;
}
public void Execute(object parameter)
{
_source.Execute(parameter);
}
public bool CanExecute(object parameter)
{
return _source.CanExecute(parameter);
}
public event System.EventHandler CanExecuteChanged = delegate { };
// Implementation.
private void OnSource_CanExecuteChanged(object sender, EventArgs args)
{
CanExecuteChanged(sender, args);
}
private void OnCommandManager_RequerySuggested(object sender, EventArgs args)
{
CanExecuteChanged(sender, args);
}
private readonly CommonUtil.Mvvm.ICommand _source;
}
}
In my Wpf assembly I also create a ValueConverter that when passed an instance of my custom ICommand spits out an instance of the Windows.Input.ICommand compatible CommandWrapper.
namespace WpfUtil
{
using System;
using System.Globalization;
using System.Windows.Data;
public class CommandConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return new CommandWrapper((CommonUtil.Mvvm.ICommand)value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
}
Now my viewmodels can expose commands as instances of my custom command type without having to have any dependency on WPF, and my UI can bind Windows.Input.ICommand commands to those viewmodels using my ValueConverter like so. (XAML namespace spam ommited).
<Window x:Class="Project1.MainWindow">
<Window.Resources>
<wpf:CommandConverter x:Key="_commandConv"/>
</Window.Resources>
<Grid>
<Button Content="Button1" Command="{Binding CustomCommandOnViewModel,
Converter={StaticResource _commandConv}}"/>
</Grid>
</Window>
Now if I'm really lazy (which I am) and can't be bothered to have to manually apply the CommandConverter every time then in my Wpf assembly I can create my own Binding subclass like this:
namespace WpfUtil
{
using System.Windows.Data;
public class CommandBindingExtension : Binding
{
public CommandBindingExtension(string path) : base(path)
{
Converter = new CommandConverter();
}
}
}
So now I can bind to my custom command type even more simply like so:
<Window x:Class="Project1.MainWindow"
xmlns:wpf="clr-namespace:WpfUtil;assembly=WpfUtil">
<Window.Resources>
<wpf:CommandConverter x:Key="_commandConv"/>
</Window.Resources>
<Grid>
<Button Content="Button1" Command="{wpf:CommandBinding CustomCommandOnViewModel}"/>
</Grid>
</Window>

I needed an example of this so I wrote one using various techniques.
I had a few design goals in mind
1 - keep it simple
2 - absolutely no code-behind in the view (Window class)
3 - demonstrate a dependency of only the System reference in the ViewModel class library.
4 - keep the business logic in the ViewModel and route directly to the appropriate methods without writing a bunch of "stub" methods.
Here's the code...
App.xaml (no StartupUri is the only thing worth noting)
<Application
x:Class="WpfApplicationCleanSeparation.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Application>
App.xaml.cs (load up the main view)
using System.Windows;
using WpfApplicationCleanSeparation.ViewModels;
namespace WpfApplicationCleanSeparation
{
public partial class App
{
protected override void OnStartup(StartupEventArgs e)
{
var view = new MainView();
var viewModel = new MainViewModel();
view.InitializeComponent();
view.DataContext = viewModel;
CommandRouter.WireMainView(view, viewModel);
view.Show();
}
}
}
CommandRouter.cs (the magic)
using System.Windows.Input;
using WpfApplicationCleanSeparation.ViewModels;
namespace WpfApplicationCleanSeparation
{
public static class CommandRouter
{
static CommandRouter()
{
IncrementCounter = new RoutedCommand();
DecrementCounter = new RoutedCommand();
}
public static RoutedCommand IncrementCounter { get; private set; }
public static RoutedCommand DecrementCounter { get; private set; }
public static void WireMainView(MainView view, MainViewModel viewModel)
{
if (view == null || viewModel == null) return;
view.CommandBindings.Add(
new CommandBinding(
IncrementCounter,
(λ1, λ2) => viewModel.IncrementCounter(),
(λ1, λ2) =>
{
λ2.CanExecute = true;
λ2.Handled = true;
}));
view.CommandBindings.Add(
new CommandBinding(
DecrementCounter,
(λ1, λ2) => viewModel.DecrementCounter(),
(λ1, λ2) =>
{
λ2.CanExecute = true;
λ2.Handled = true;
}));
}
}
}
MainView.xaml (there is NO code-behind, literally deleted!)
<Window
x:Class="WpfApplicationCleanSeparation.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfApplicationCleanSeparation="clr-namespace:WpfApplicationCleanSeparation"
Title="MainWindow"
Height="100"
Width="100">
<StackPanel>
<TextBlock Text="{Binding Counter}"></TextBlock>
<Button Content="Decrement" Command="WpfApplicationCleanSeparation:CommandRouter.DecrementCounter"></Button>
<Button Content="Increment" Command="WpfApplicationCleanSeparation:CommandRouter.IncrementCounter"></Button>
</StackPanel>
</Window>
MainViewModel.cs (includes the actual Model as well since this example is so simplified, please excuse the derailing of the MVVM pattern.
using System.ComponentModel;
namespace WpfApplicationCleanSeparation.ViewModels
{
public class CounterModel
{
public int Data { get; private set; }
public void IncrementCounter()
{
Data++;
}
public void DecrementCounter()
{
Data--;
}
}
public class MainViewModel : INotifyPropertyChanged
{
private CounterModel Model { get; set; }
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public MainViewModel()
{
Model = new CounterModel();
}
public int Counter
{
get { return Model.Data; }
}
public void IncrementCounter()
{
Model.IncrementCounter();
PropertyChanged(this, new PropertyChangedEventArgs("Counter"));
}
public void DecrementCounter()
{
Model.DecrementCounter();
PropertyChanged(this, new PropertyChangedEventArgs("Counter"));
}
}
}
Just a quick and dirty and I hope it's useful to someone. I saw a few different approaches through various Google's but nothing was quite as simple and easy to implement with the least amount of code possible that I wanted. If there's a way to simplify even further please let me know, thanks.
Happy Coding :)
EDIT: To simplify my own code, you might find this useful for making the Adds into one-liners.
private static void Wire(this UIElement element, RoutedCommand command, Action action)
{
element.CommandBindings.Add(new CommandBinding(command, (sender, e) => action(), (sender, e) => { e.CanExecute = true; }));
}

Instead of the VM exposing commands, just expose methods. Then use attached behaviors to bind events to the methods, or if you need a command, use an ICommand that can delegate to these methods and create the command through attached behaviors.

Off course this is possible. You can create just another level of abstraction.
Add you own IMyCommand interface similar or same as ICommand and use that.
Take a look at my current MVVM solution that solves most of the issues you mentioned yet its completely abstracted from platform specific things and can be reused. Also i used no code-behind only binding with DelegateCommands that implement ICommand. Dialog is basically a View - a separate control that has its own ViewModel and it is shown from the ViewModel of the main screen but triggered from the UI via DelagateCommand binding.
See full Silverlight 4 solution here Modal dialogs with MVVM and Silverlight 4

I think you are separating your Project at wrong point. I think you should share your model and business logic classes only.
VM is an adaptation of model to suit WPF Views. I would keep VM simple and do just that.
I can't imagine forcing MVVM upon Winforms. OTOH having just model & bussiness logic, you can inject those directly into a Form if needed.

" you can't reuse a WPF MVVM in a WinForms application"
For this please see url http://waf.codeplex.com/ , i have used MVVM in Win Form, now whenver i would like to upgrade application's presentation from Win Form to WPF, it will be changed with no change in application logic,
But i have one issue with reusing ViewModel in Asp.net MVC, so i can make same Desktop win application in Web without or less change in Application logic..
Thanks...

Related

WPF, MVVM IoC: Alternative to Service Locator Pattern. Need dependency in View code behind

Following several guides I have a application layout like below using WPF .NET 4.7.1 and MVVM-Light. I'm totally new to WPF btw.
App.xaml:
<Application x:Class="My.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewmodel="clr-namespace:My.ViewModel"
StartupUri="View\MainView.xaml">
<Application.Resources>
<ResourceDictionary>
<viewmodel:ViewModelLocator x:Key="Locator" />
</ResourceDictionary>
</Application.Resources>
That registers the "ViewModelLocator" class as a resources and sets the WPF startup to "View/MainView.xaml".
MainView.xaml:
<Window x:Class="My.View.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.DataContext>
<Binding Path="Main" Source="{StaticResource Locator}"/>
</Window.DataContext>
Where the ViewModelLocator is used like a Service Locator Pattern. Here setting the DataContext to my "MainViewModel" (not shown). As much as I do not like this, I can live with it in the WPF XAML context. However now it turns out that I need a dependency in the code-behind of the view (not the ViewModel).
MainView.cs:
public partial class MainView : INotifyPropertyChanged
{
public MainView()
{
// Need to access dependency here.
}
}
Now I could just call the ViewModelLocator directly in that constructor and have that resolve from my IoC container - but then I've completely given in and accepting that pattern.
I would prefer to have the dependency injected in the ctor of course, and if that is possible, I would also leave the ViewModelLocator entirely and inject the ViewModel here.
So question is, are there some standard way of instructing WPF application to use my container? And if yes, is it adviceable to go down that path and not use the ViewModelLocator thing?
You absolutely do not have to use the ViewModelLocator (Side note, the service locator pattern has had it's fair share of criticism lately as an anti-pattern, but I'll let you form your own opinion). MVVM Light and other Libraries basically give you access to a tool kit. You don't need to use all of the tools, and you should only use what is necessary for your specific domain.
Outside of the ViewModelLocator, there are two patterns known as ViewModel First and View First both have their pro's and cons. However both provide a means to decouple your code, which means it's not difficult to switch later.
As for constructing an application using MVVM Light without the service locator, my implementation of the View First method looks something like this.
I've heard the opinion that ViewModel First is preferred, however I find View First to be more simplistic for Test Driven Development (TDD)
App.xaml.cs (Application Code Behind)
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var bootStrapper = new BootStrapper();
//Container Builder
var container = bootStrapper.BootStrap();
var mainWindow = container.Resolve<MainWindow>();
mainWindow.Show();
}
}
BootStrapper.cs (I'm using AutoFac in this case, but you can easily substitute.)
public class BootStrapper
{
public IContainer BootStrap()
{
var builder = new ContainerBuilder();
builder.RegisterType<MainWindow>().AsSelf();
builder.RegisterType<MainWindowViewModel>().AsSelf();
return builder.Build();
}
}
MainWindowViewModel.cs
//I rolled my own ViewModelBase, but you can use MVVM Light's ViewModelBase
public class MainWindowViewModel : ViewModelBase
{
public string DisplayProgram
{
get { return _displayProgram; }
//MVVM Light's ViewModelBase uses RaisePropertyChanged();
set { _displayProgram = value; OnPropertyChanged(); }
}
public void Initialize()
{
//Called from view code behind.
}
}
MainWindow.xaml.cs (MainWindow Code Behind)
//When MainWindow.Show()..
public partial class MainWindow : Window
{
private readonly MainWindowViewModel _viewModel;
//Container resolves dependencies
public MainWindow(MainWindowViewModel viewModel)
{
//Let base Window class do its thing.
InitializeComponent();
//Handle loaded event
Loaded += MainWindowLoaded;
//Hold on to the MainWindowViewModel, and set it as the windows DataContext
_viewModel = viewModel;
DataContext = _viewModel;
}
private void MainWindowLoaded(object sender, RoutedEventArgs e)
{
_viewModel.Initialize();
}
}

MVVM pattern violation: MediaElement.Play()

I understand that ViewModel shouldn't have any knowledge of View, but how can I call MediaElement.Play() method from ViewModel, other than having a reference to View (or directly to MediaElement) in ViewModel?
Other (linked) question: how can I manage View's controls visibility from ViewModel without violating MVVM pattern?
1) Do not call Play() from the view model. Raise an event in the view model instead (for instance PlayRequested) and listen to this event in the view:
view model:
public event EventHandler PlayRequested;
...
if (this.PlayRequested != null)
{
this.PlayRequested(this, EventArgs.Empty);
}
view:
ViewModel vm = new ViewModel();
this.DataContext = vm;
vm.PlayRequested += (sender, e) =>
{
this.myMediaElement.Play();
};
2) You can expose in the view model a public boolean property, and bind the Visibility property of your controls to this property. As Visibility is of type Visibility and not bool, you'll have to use a converter.
You can find a basic implementation of such a converter here.
This related question might help you too.
For all the late-comers,
There are many ways to achieve the same result and it really depends on how you would like to implement yours, as long as your code is not difficult to maintain, I do believe it's ok to break the MVVM pattern under certain cases.
But having said that, I also believe there is always way to do this within the pattern, and the following is one of them just in case if anyone would like to know what other alternatives are available.
The Tasks:
we don't want to have direct reference from the ViewModel to any UI elements, i.e. the the MediaElement and the View itself.
we want to use Command to do the magic here
The Solution:
In short, we are going to introduce an interface between the View and the ViewModel to break the dependecy, and the View will be implementing the interface and be responsible for the direct controlling of the MediaElement while leaving the ViewModel talking only to the interface, which can be swapped with other implementation for testing purposes if needed, and here comes the long version:
Introduce an interface called IMediaService as below:
public interface IMediaService
{
void Play();
void Pause();
void Stop();
void Rewind();
void FastForward();
}
Implement the IMediaService in the View:
public partial class DemoView : UserControl, IMediaService
{
public DemoView()
{
InitializeComponent();
}
void IMediaService.FastForward()
{
this.MediaPlayer.Position += TimeSpan.FromSeconds(10);
}
void IMediaService.Pause()
{
this.MediaPlayer.Pause();
}
void IMediaService.Play()
{
this.MediaPlayer.Play();
}
void IMediaService.Rewind()
{
this.MediaPlayer.Position -= TimeSpan.FromSeconds(10);
}
void IMediaService.Stop()
{
this.MediaPlayer.Stop();
}
}
we then do few things in the DemoView.XAML:
Give the MediaElement a name so the code behind can access it like above:
<MediaElement Source="{Binding CurrentMedia}" x:Name="MediaPlayer"/>
Give the view a name so we can pass it as a parameter, and
import the interactivity namespace for later use (some default namespaces are omitted for simplicity reason):
<UserControl x:Class="Test.DemoView"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ia="http://schemas.microsoft.com/expression/2010/interactivity"
x:Name="MediaService">
Hookup the Loaded event through Trigger to pass the view itself to the view model through a Command
<ia:Interaction.Triggers>
<ia:EventTrigger EventName="Loaded">
<ia:InvokeCommandAction Command="{Binding LoadedCommand}" CommandParameter="{Binding ElementName=MediaService}"></ia:InvokeCommandAction>
</ia:EventTrigger>
</ia:Interaction.Triggers>
last but not least, we need to hookup the media controls through Commands:
<Button Command="{Binding PlayCommand}" Content="Play"></Button>
<Button Command="{Binding PauseCommand}" Content="Pause"></Button>
<Button Command="{Binding StopCommand}" Content="Stop"></Button>
<Button Command="{Binding RewindCommand}" Content="Rewind"></Button>
<Button Command="{Binding FastForwardCommand}" Content="FastForward"></Button>
We now can catch everything in the ViewModel (I'm using prism's DelegateCommand here):
public class AboutUsViewModel : SkinTalkViewModelBase, IConfirmNavigationRequest
{
public IMediaService {get; private set;}
private DelegateCommand<IMediaService> loadedCommand;
public DelegateCommand<IMediaService> LoadedCommand
{
get
{
if (this.loadedCommand == null)
{
this.loadedCommand = new DelegateCommand<IMediaService>((mediaService) =>
{
this.MediaService = mediaService;
});
}
return loadedCommand;
}
}
private DelegateCommand playCommand;
public DelegateCommand PlayCommand
{
get
{
if (this.playCommand == null)
{
this.playCommand = new DelegateCommand(() =>
{
this.MediaService.Play();
});
}
return playCommand;
}
}
.
. // other commands are not listed, but you get the idea
.
}
Side note: I use Prism's Auto Wiring feature to link up the View and ViewModel. So at the View's code behind file there is no DataContext assignment code, and I prefer to keep it that way, and hence I chose to use purely Commands to achieve this result.
I use media element to play sounds in UI whenever an event occurs in the application. The view model handling this, was created with a Source property of type Uri (with notify property changed, but you already know you need that to notify UI).
All you have to do whenever source changes (and this is up to you), is to set the source property to null (this is why Source property should be Uri and not string, MediaElement will naturally throw exception, NotSupportedException I think), then set it to whatever URI you want.
Probably, the most important aspect of this tip is that you have to set MediaElement's property LoadedBehaviour to Play in XAML of your view. Hopefully no code behind is needed for what you want to achieve.
The trick is extremely simple so I won't post a complete example. The view model's play function should look like this:
private void PlaySomething(string fileUri)
{
if (string.IsNullOrWhiteSpace(fileUri))
return;
// HACK for MediaElement: to force it to play a new source, set source to null then put the real source URI.
this.Source = null;
this.Source = new Uri(fileUri);
}
Here is the Source property, nothing special about it:
#region Source property
/// <summary>
/// Stores Source value.
/// </summary>
private Uri _Source = null;
/// <summary>
/// Gets or sets file URI to play.
/// </summary>
public Uri Source
{
get { return this._Source; }
private set
{
if (this._Source != value)
{
this._Source = value;
this.RaisePropertyChanged("Source");
}
}
}
#endregion Source property
As for Visibility, and stuff like this, you can use converters (e.g. from bool to visibility, which you can find on CodePlex for WPF, SL, WP7,8) and bind your control's property to that of the view model's (e.g. IsVisible). This way, you control parts of you view's aspect. Or you can just have Visibility property typed System.Windows.Visibility on your view model (I don't see any pattern breach here). Really, it's not that uncommon.
Good luck,
Andrei
P.S. I have to mention that .NET 4.5 is the version where I tested this, but I think it should work on other versions as well.

Double Click on a WPF ListView - how to fire a command and not use an event handler

I am a little confused on how to implement an event as a command in my particular situation. I want to honour MVVM, but don't get how in this case.
I have a WPF 'view' - viewCustomerSearch. This has some text boxes on it, and when the user clicks 'Search' the results are populated in ListView. viewCustomerSearch is bound to viewmodelCustomerSearch, and it works great.
viewCustomerSearch is hosted on viewCustomer.
I want to know have viewCustomerSearch expose a custom command - CustomerSelectedCommand - that is 'fired' whenever the ListView in viesCustomerSearch is double clicked, and then handled by the viewmodel behind viewCustomer (which is viewmodelCustomer). This seems the theoretical MVVM pattern implemented correctly.
I have broken down the main problem into three smaller problems, but hopefully you can see they are all components of the same challenge.
FIRST PROBLEM: in order to have viewCustomerSearch expose a custom command I seem to have to put this code in viewCustomerSearch - which seems to 'break' MVVM (no code in the view code behind).
public readonly DependencyProperty CustomerSelectedCommandProperty = DependencyProperty.Register("CustomerSelectedCommand", typeof(ICommand), typeof(viewCustomerSearch));
public ICommand CustomerSelectedCommand
{
get { return (ICommand)GetValue(CustomerSelectedCommandProperty); }
set { SetValue(CustomerSelectedCommandProperty, value); }
}
SECOND PROBLEM (and this is the one that is really getting to me): Best explained by showing what I would do which breaks MVVM. I would have an event handler in the view:
private void lstResults_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (CustomerSelectedCommand != null) CustomerSelectedCommand.Execute(((ViewModels.viewmodelCustomerSearchResult)this.lstResults.SelectedItem).CustomerId);
}
Well ... I know that you shouldn't put this event handler here; rather it should have a Command to handle it in the viewmodelCustomerSearch. The two problems here are
because the 'CustomerSelectedCommand' ICommand is implemented in
viewCustomerSearch, viewmodelCustomerSearch can't see it to fire it.
I cannot see how to bind the MouseDoubleClick event to a command, instead of an event handler in the view code behind. I am reading about Attached Properties, but cannot see how they are to be applied here.
(Please note: I am using the common 'RelayCommand' elsewhere in the application; does this come into play here??)
THIRD PROBLEM: When I do use the non-MVVM way of firing the command in the code behind event handler, you can see that I am passing in the Selected Customer Id as an arguement into the command. How do I see that argument in the Command handler in viewCustomer? I create a new RelayCommand to handle it, but it seems the Execute method does not take arguments?
Given all of the above, I have to say that I do NOT personally subscribe to the 'MVVM means NO CODE IN THE VIEW'. That seems crazy to me; code that is entirely to do with the view, and the view only, should not - IMHO - go in the viewmodel. That said, though, this does seem like logic-y stuff (not view stuff).
Many thanks for some insight. Sorry for the long post; trying to balance enough information for you to help me with 'War and Peace'.
DS
In your view you can add a "Command" property in xaml and bind it to your ViewModel's command
Command="{Binding CustomerSelectedCommand}"
Parameters can be passed in multiple ways. Most of the time, I just have other items bound to my ViewModel and I can just use them directly. However there is also a property called CommandParameter, here's an example of specifying it in XAML.
CommandParameter="{Binding ElementName=txtPassword}"
then in my ViewModel the definition of my Command looks like this
private void UserLogonCommandExecute(object parameter)
{
...
var password_box = parameter as PasswordBox;
...
}
It sounds like you already know how to set up a RelayCommand in your ViewModel so I won't go into that. I found How Do I: Build Data-driven WPF Application using the MVVM pattern helpful when I was getting started.
Per Comment Request Command Property Example
I'm just going to grab some working code, here's how you add a Command property to a button in XAML.
<Button Command="{Binding ConnectCommand}">
//Your button content and closing </Button> here
This assume you have set your DataContext to a ViewModel that has a Command called ConnectCommand. Here's an example for ConnectCommand. You'll need to replace the contents of ConnectCommandCanExecute and ConnectCommandExecute with whatever work you want done.
public ICommand ConnectCommand
{
get
{
if (_connectCommand == null)
{
_connectCommand = new RelayCommand(param => ConnectCommandExecute(),
param => ConnectCommandCanExecute);
}
return _connectCommand;
}
}
private bool ConnectCommandCanExecute
{
get { return !_instrumentModel.IsConnected; }
}
private void ConnectCommandExecute()
{
if (TcpSettingsChanged()) SaveTcpSettings();
_instrumentModel.Connect(_tcpData);
}
RelayClass
One part of making this simple is the RelayClass I have in one of my core library .dlls. I probably got this from one of the videos I watched. This can be cut and pasted in it's entirety, there is nothing here you need to customize, except you'll probably want to change the namespace this is in.
using System;
using System.Diagnostics;
using System.Windows.Input;
namespace Syncor.MvvmLib
{
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public RelayCommand(Action<object> execute)
: this(execute, (Predicate<object>) null)
{
this._execute = execute;
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
this._execute = execute;
this._canExecute = canExecute;
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
if (this._canExecute != null)
return this._canExecute(parameter);
else
return true;
}
public void Execute(object parameter)
{
this._execute(parameter);
}
}
}
Why don't you name it "DoubleClickCommand" that way you don't put business logic in your control. And then bind this command to your viewmodel, Like Tod explained.
Regarding your code behind, there is a pure xaml solution, to be more precise it involves attached behaviors, but does not need to override a WPF class(which i like to avoid), search for "fire command on event" for example this.
One final thing: Code Behind does NOT break MVVM in any way, i wonder where this myth came from. Code behind is perfectly fine! MVVM is to separate view and logic, not telling you where to put your code. Design principles should help, not hinder you.

RaiseCanExecuteChanged event

I am at the stage in a project where I need to get control of enabling / disabling some hyperlinks based on various business rules. I noticed all topics on RaiseCanExecuteChanged event refer to MVVM light. Does this mean that I have to use MVVM light or is there a way to access this event using standard MVVM. If so, how? Thanks
ICommands have an event that command watchers subscribe to. When this event fires, it is the responsibility of the watchers (Button, etc) to call CanExecute in order to determine if they should enable/disable themselves.
As you must implement ICommand, you must also provide a way for your ViewModels (or whatever, depending on your design) to fire this event from outside the ICommand instance. How you go about this is up to you. It is common (in my experience) to place a method on your ICommand implementation called something like FireCanExecuteChanged which you can call to inform the instance that they should fire the CanExecute event.
Here's an example in vaguely c#-like pseudocode.
public sealed class MyViewModel
{
// dependencyproperty definition left off for brevity
public MyCommand ACommand {get;private set;}
// fired when some DP changes which affects if ACommand can fire
private static void OnSomeDependencyPropertyChanged
(object sender, EventArgs e)
{
(sender as MyViewModel).ACommand.FireCanExecuteChanged();
}
}
public sealed class MyCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public bool CanExecute(object arg) { return arg != null; }
public void Execute(object arg) { throw new NotImplementedException(); }
public void FireCanExecuteChanged() {
CanExecuteChanged(this, EventArgs.Empty); }
}

PropertyChangedEventHandler always null in silverlight binding

I've been trying to resolve this issue for some time.
I'm trying to bind a TextBlock's text to a string property using the INotifyPropertyChanged interface. For some reason the PropertyChangedEventHandler is always null when the value of the property is changed thus the target never gets updated...
Any suggestions?
Code below:
XAML code:
<UserControl x:Class="MoleDashboard.MainPage"
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:basics="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
xmlns:datacontrols="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Data"
xmlns:prop="clr-namespace:MoleDashboard"
<UserControl.Resources>
<prop:YearScreen x:Key="YearScreenProps"/>
</UserControl.Resource>
<TextBlock Margin="10 5" x:Name="DataGridLabel" Visibility="Visible" Text="{Binding YearProperty, Source={StaticResource YearScreenProps}, Mode=OneWay}"/>
Bound property code:
public class YearScreen : INotifyPropertyChanged
{
private string metricProperty;
private string yearProperty;
public event PropertyChangedEventHandler PropertyChanged;
public YearScreen()
{
}
public string YearProperty
{
get { return yearProperty; }
set { yearProperty = value; this.OnPropertyChanged("YearProperty"); }
}
public string MetricProperty
{
get { return metricProperty; }
set { metricProperty = value; this.OnPropertyChanged("MetricProperty"); }
}
public void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
This is based on the comments provided and not just the question above.
Basically the problem is that you are creating updating a second instance of your ViewModel (called a YearScreen in your code) and updating that.
A YearScreen is already being created and bound to your Xaml, by the inclusion of:
<UserControl.Resources>
<prop:YearScreen x:Key="YearScreenProps"/>
</UserControl.Resource>
You are then creating a second ViewScreen elsewhere in code (via new ViewScreen()) and updating that, however there is no connection between the 2 ViewScreen instances, so nothing will update in the Xaml page.
One Possible (quick) solution:
Create your YearScreen as a singleton. That is add a static accessor of type YearScreen in the class and set it from the constructor.
public class YearScreen : INotifyPropertyChanged
{
private static YearScreen _This;
public static YearScreen This { get { return _This; } }
[snip]
public YearScreen()
{
_This = this;
}
The you can access the "single" instance of your YearScreen from elsewhere using the static singleton accessor e.g.:
YearScreen.This.YearProperty = DateTime.Now.ToString():
There are better patterns for sharing ViewModels than singletons, but that will get you going.
The pattern you started with is ViewFirst creation (the view creates the ViewModel). ModelFirst does the opposite, but is bad as the model knows how it is displayed. Using a controller object to create the View and ViewModel and connect them is a better alternative, but that is then getting quite complicated. Using injection of single instance objects is a better option, but involves a whole load of new concepts. Lookup Silverlight Prism after you solve your current problems.
Instead of creating the ViewModel in the resources you should set it into the DataContext of the view from external code.
If you really want to put it in the Resources like that you can get it out of the resources in the code behind Loaded method or in the constructor after the initializecomponent call. Like so:
private YearScreen model;
public MainPage()
{
this.Loaded += MainPage_Loaded;
this.InitializeComponent();
}
void MainPage_Loaded(object sender, EventArgs e)
{
this.model = (YearScreen)this.Resources["YearScreenProps"];
}
Maybe expose it as a property so you can then access it externally. But personally I'd rather create the model externally than pass it into the View instead. Put it into the DataContext.

Resources