Hi Grant,
The thing about MVVM is that to do it, you really just need:
1) A base class for a view model (i.e., a class that implements
INotifyPropertyChanged)
2) A delegate command
Most of the MVVM "frameworks" are just that, though some have a couple of extra
features thrown in (Caliburn, for example, is a whole lot more). The simplicity
of the pattern is why so many implementations have been published - it's like
people creating frameworks for the Singleton pattern :)
I've attached the base view model I'm using on a current project - you can see
how simple it is. I started writing some pages about how Magellan can integrate
with MVVM frameworks, but after the third one I stopped evaluating them because
they nearly all worked the same way.
When it comes to MVVM I'd actually encourage everyone to write and use their
own (though certainly keeping an eye on what others have done) since it's nice
to evolve it for your particular application. Most of the frameworks are so
simple I wouldn't bother with a binary dependency on them. MicroModels is a
little different because the terseness it enables is only possible through a
lot of framework code (type descriptors, etc.) that you might prefer a binary
dependency.
As far as a unified framework goes, I actually think it's likely Microsoft will
do something in this space, either with Prism vNext or WPF 5.0. I haven't heard
anything to say for sure, but I'd be very surprised if they don't - see this
thread for an
example<http://groups.google.com/group/wpf-disciples/browse_thread/thread/32e3756952f7a7e8>.
They already took a stab at it with the MVVM
Toolkit<http://wpf.codeplex.com/wikipage?title=WPF%20Model-View-ViewModel%20Toolkit&referringTitle=Home>
(which is as good a starting point as any).
Paul
From: [email protected] [mailto:[email protected]] On
Behalf Of Grant Molloy
Sent: Wednesday, 17 March 2010 10:11 PM
To: ozWPF
Subject: Re: MicroModels question
There's so many out there (plenty of which are made by Paul's colleagues at WPF
Deciples) at the moment the hardest part is making a choice...
Caliburn (Codeplex)
Calcium (codeplex)
MVVM Light (galasoft)
Cinch (codeplex)
MVVM Foundation (codeplex)
Ocean (Karl on WPF)
WPF Onyx (codeplex)
MicroModels (paulstovell.com<http://paulstovell.com>)
I've used MVVM Light, Cinch and Ocean..
I'm currently looking at Calcium....
I wish there was a combination of all for a best of breed solution..
Paul, maybe you could organise this project, or plant the seed, with your WPF
Deciple colleagues and start a WPF Deciples MVVM Framework where the best bits
of all the frameworks are bought together ?
On Wed, Mar 17, 2010 at 8:12 PM, Rui Miguel Pires Soares Marinho
<[email protected]<mailto:[email protected]>> wrote:
MVVM light imo it's a great framework to start with mvvm and even for complex
scenarios, it helps alot having templates to start your projects.
regards Rui
Rui Marinho
Software Developer
_____________________________________________________
M:
T:
+351 914408168
+351 912358027
Hospital São João
Alameda Professor Hernâni Monteiro
4200-319 Porto
De: [email protected]<mailto:[email protected]>
[mailto:[email protected]<mailto:[email protected]>] Em
nome de Adrian Hara
Enviada: terça-feira, 16 de Março de 2010 15:59
Para: ozWPF
Assunto: RE: MicroModels question
Hi Paul,
Thanks for the reply.
It's too bad that you don't intend on improving the MicroModels framework, I
find it's really cool. What MVVM Framework do you use or recommend in your
daily work?
Adrian
From: [email protected]<mailto:[email protected]>
[mailto:[email protected]<mailto:[email protected]>] On
Behalf Of Paul Stovell
Sent: Tuesday, March 16, 2010 11:49 AM
To: ozWPF
Subject: RE: MicroModels question
Hi Adrian,
The implementation should probably do that as it does allow some things to
work. Personally I never really liked that event - I find it very half-baked
and crying out as a performance bottleneck - so it's never front-of-mind when
writing custom delegates.
What I would have liked to have done would be to use expression dependencies to
trigger the CanExecuteChanged event. So something like this would work:
Command("Save", ()=>DoSave(), () => HasChanges)
The command's CanExecuteChanged event would be raised whenever HasChanges
property changed event is raised.
I should add - as it wasn't clear on my initial blog post - that MicroModels
was a "throw it out and see if it sticks" project. The code isn't very mature
and I don't have any plans to improve on it, it was purely a fun thing (unlike
Magellan which I am using and do maintain). If it's working for you then that's
good but expect to make a few changes as you have done :)
Paul
From: [email protected]<mailto:[email protected]>
[mailto:[email protected]<mailto:[email protected]>] On
Behalf Of Adrian Hara
Sent: Tuesday, 16 March 2010 5:04 PM
To: ozWPF
Subject: RE: MicroModels question
Hi Paul,
Thanks for the answer, this is exactly what I did, I was just wondering if
there was a more MicroModelsy solution :)
In the meantime I've another question: why doesn't the MicroModels
implementation of DelegateCommand use CommandManager.RequerySuggested for its
implementation of the CanExecuteChanged event? I found that using the current
implementation doesn't requery the CanExecute delegate when the UI state
changes (i.e. it's only queried once, when the command is bound, then never
again).
I changed the implementation of the CanExecuteChanged event to look like so:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
...and now the CanExecute delegate is requeried whenever the UI state changes
(e.g. user presses a button).
What do you think about this, is this ok?
Thanks,
Adrian
From: [email protected]<mailto:[email protected]>
[mailto:[email protected]<mailto:[email protected]>] On
Behalf Of Paul Stovell
Sent: Tuesday, March 16, 2010 1:35 AM
To: ozWPF
Subject: RE: MicroModels question
Hi Adrian,
I haven't tried, but something like this might work:
private Foo _foo;
public Foo Foo
{
get { return _foo; }
set { _foo = value; NotifyChanged("Foo"); }
}
public FooViewModel(Foo foo, Baz baz)
{
Foo = foo;
Property(() => Foo.Bar);
baz.SomeEvent += () => Foo = new Foo();
}
By doing this, the MicroModels expression walker should also subscribe to the
Foo property change event and re-evaluate when it changes.
Paul
From: [email protected]<mailto:[email protected]>
[mailto:[email protected]<mailto:[email protected]>] On
Behalf Of Adrian Hara
Sent: Monday, 15 March 2010 7:16 PM
To: [email protected]<mailto:[email protected]>
Subject: MicroModels question
Hi,
I'm playing with the very-cool MicroModels framework from Paul Stovell, but I
have a question. Suppose I have this view model
Class FooViewModel : MicroModel
{
Public FooViewModel(Foo foo, Baz baz)
{
Property(() => foo.Bar);
baz.SomeEvent += () => foo = new Foo();
}
}
So the idea is that the underlying domain object upon which the view model is
based (in this case the instance of Foo) can change (e.g. in response to some
event). In this case the micro-model properties are "lost", i.e. they are still
"subscribed" to the old instance of Foo and not to the new one.
What would be a good solution in this case so the properties get re-wired to
use the new instance of Foo?
Thanks,
Adrian
_______________________________________________
ozwpf mailing list
[email protected]<mailto:[email protected]>
http://prdlxvm0001.codify.net/mailman/listinfo/ozwpf
using System;
using System.ComponentModel;
namespace Z.ProvisioningVerification.Framework
{
public class BusyState : INotifyPropertyChanged
{
private int _waitingTasks;
public event PropertyChangedEventHandler PropertyChanged;
public bool IsBusy
{
get { return _waitingTasks > 0; }
}
public bool IsNotBusy
{
get { return !IsBusy; }
}
public IDisposable Enter()
{
_waitingTasks++;
OnPropertyChanged(new PropertyChangedEventArgs("IsBusy"));
OnPropertyChanged(new PropertyChangedEventArgs("IsNotBusy"));
return new StateEntrance(this);
}
public void Exit()
{
_waitingTasks--;
OnPropertyChanged(new PropertyChangedEventArgs("IsBusy"));
OnPropertyChanged(new PropertyChangedEventArgs("IsNotBusy"));
}
private void OnPropertyChanged(PropertyChangedEventArgs e)
{
var handler = PropertyChanged;
if (handler != null) handler(this, e);
}
private class StateEntrance : IDisposable
{
private readonly BusyState _busyState;
public StateEntrance(BusyState busyState)
{
_busyState = busyState;
}
public void Dispose()
{
_busyState.Exit();
}
}
}
}using Magellan.Framework;
namespace Z.ProvisioningVerification.Framework
{
public class ViewModel : Observable, INavigationAware
{
private readonly BusyState _busyState;
public ViewModel()
{
_busyState = new BusyState();
}
public BusyState BusyState
{
get { return _busyState; }
}
public NavigationContext NavigationContext { get; set; }
}
}
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace Z.ProvisioningVerification.Framework
{
/// <summary>
/// A base class for objects that implement the INotifyPropertyChanged
interface.
/// </summary>
public abstract class Observable : INotifyPropertyChanged
{
private IEnumerable<string> _propertyNames;
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises the <see cref="PropertyChanged"/> event for every public
property on this object.
/// </summary>
protected void NotifyChanged()
{
if (_propertyNames == null)
{
_propertyNames =
TypeDescriptor.GetProperties(this).OfType<PropertyDescriptor>().Select(x =>
x.Name).ToArray();
}
NotifyChanged(_propertyNames);
}
/// <summary>
/// Raises the <see cref="PropertyChanged"/> event for each event in
the collection.
/// </summary>
/// <param name="propertyNames">The property names.</param>
protected void NotifyChanged(IEnumerable<string> propertyNames)
{
foreach (var property in propertyNames.Distinct())
{
OnPropertyChanged(new PropertyChangedEventArgs(property));
}
}
/// <summary>
/// Raises the <see cref="PropertyChanged"/> event for the given
property names.
/// </summary>
/// <param name="propertyName">The name of the property that has
changed</param>
/// <param name="additionalPropertyNames">Any other properties that
also changed.</param>
protected void NotifyChanged(string propertyName, params string[]
additionalPropertyNames)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
NotifyChanged(additionalPropertyNames);
}
/// <summary>
/// Raises the <see cref="PropertyChanged"/> event.
/// </summary>
/// <param name="e">The <see
cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the
event data.</param>
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
var handler = PropertyChanged;
if (handler != null) handler(this, e);
}
}
}_______________________________________________
ozwpf mailing list
[email protected]
http://prdlxvm0001.codify.net/mailman/listinfo/ozwpf