Sharing DataContext to UserControl in a type safe way - silverlight

I'm developing my first Silverlight 4 app and are struggling on how to to share my DataContext set on the top element (a Grid) in my MainPage.xaml into an underlying UserControl, in a type safe way. The DataContext is an instance of my ViewModel class and my thought is to be able to bind certain elements in the UserControl to properties of the ViewModel.
I am pretty sure the ViewModel object bubbles down to my UserControl but how can I in the UserControl asure that the DataContext is of type PatternCreatorViewModel?
Hope this was understandable!

This is (in my lonely opinion) one of the biggest limitations of the data binding model in Silverlight and WPF, namely, that there's no type safety anywhere in the process. As soon as you type {Binding...} you're working without a net. MS managed to take a wonderfully glorious strongly-typed language like C# and tied it to a completely non-type-safe data binding model, thereby all but wrecking a decade of Anders Hejlsberg's wonderful work on C#. You expect this sort of "looseness" when working with dynamic languages, but not when you're dealing with C#.
This limitation really becomes problematic when you're changing the ViewModel underlying your Views, because of course, there's no easy way to test your data bindings. Normally, when you've got code that you can't test, you can at least rely on the compiler to tell you if what you're asking the code to do doesn't make any sense. But because MS made data bindings non-type-safe, not only can you not test your changes, you can't even rely on the compiler to tell you when they don't make any sense. And, to add insult to injury, you can't even rely on running your application and seeing if you get any error messages: because bindings always fail silently. The best you can do is turn up the logging level and walk through tons of debug error messages. Uggh. Nasty as hell.
See my blog posting here, another question I asked here, and my answer here for more thoughts on the underlying issue.
I should note that I seem to be virtually alone in my opinion about this one, so perhaps there's something huge that I'm just missing. But I personally think you've hit the nail right on the head.

Pleasd see update below: the first proposed solution may cause threading-issues.
One possibility is creating a DependencyProperty of the required type, updating that during DataContextChanged and binding to that.
DefaultEditor.xaml.cs:
public partial class DefaultEditor : UserControl
{
public DefaultEditor()
{
this.DataContextChanged += OnDataContextChanged;
InitializeComponent();
}
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
SetValue(propertyNameProperty, this.DataContext as IPropertyProvider);
}
public static readonly DependencyProperty propertyNameProperty = DependencyProperty.Register(
nameof(PropertyProvider), typeof(IPropertyProvider), typeof(DefaultEditor), new PropertyMetadata(default(IPropertyProvider)));
public IPropertyProvider PropertyProvider
{
get { return (IPropertyProvider)GetValue(propertyNameProperty); }
}
}
Note: I reduced the standard Visual Studio pattern for the DepenendencyProperty, because I did not want a public setter.
Also, make sure to add the event handler before calling InitializeComponent().
DefaultEditor.xaml:
<UserControl x:Class="MyApp.DefaultEditor" x:Name="self">
<Grid DataContext="{Binding ElementName=self, Path=PropertyProvider}">
<StackPanel>
<TextBlock Text="{Binding Index}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</Grid>
</UserControl>
Once x:Name="self" is defined I have Intellisense for Path=PropertyProvider and the other bindings.
Note: Be sure not to set the entire control's DataContext (which would be recursive), use another (top-level) element like the Grid.
And, in case it wasn't obvious: In the example above IPropertyProvider is a custom type that must be replaced with the required type.
UPDATE:
While the above does work, it can invite code to access DefaultEditor.PropertyProvider from a wrong thread (other than the element's dispatcher's thread), which leads to an InvalidOperationException. This can be resolved by replacing the DependencyProperty with a simple property and implementing INotifyPropertyChanged.
Here's an updated code-behind, the .xaml remains the same.
DefaultEditor.xaml.cs
public partial class DefaultEditor : UserControl, INotifyPropertyChanged
{
public DefaultEditor()
{
this.DataContextChanged += OnDataContextChanged;
InitializeComponent();
}
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
PropertyProvider = this.DataContext as IPropertyProvider;
}
private IPropertyProvider _propertyProvider;
public IPropertyProvider PropertyProvider { get => _propertyProvider; private set => SetField(ref _propertyProvider, value); }
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
#endregion
}
Note: The INotifyPropertyChanged implementation is a Visual Studio (Resharper?) code-snippet.
Using this code, DefaultEditor.PropertyProvider can be accessed from any thread.

Related

Is ViewModel allowed to close the window?

Recently I answered a question How to Bind to window's close button the X-button with what I thought was an MVVM solution. Please don't focus on actual question there, because that's not what's bothering me. I wouldn't even use my solution there in that particular case. I would most certainly use #ChrisW's solution.
Then response from #SpikeX appeared and now I am confused. But I have to thank him for that. I can't stop thinking about that, because untill now I was probably thinking about MVVM in wrong way.
So I started research:
Close Window from ViewModel
Basic concepts of MVVM— what should a ViewModel do?
and so on...
As you can see I am not the only person in the universe who closed window from ViewModel. But can I really do that? Or is it really true that I should not use window in ViewModel. Is MVVM really so strict about this? Is really my solution breaking an MVVM pattern?
Well, in my opinion the viewmodel should be completely isolated from the client technology in which it is being used.
Since you call the close method on the actual Window instance, you need a reference to a client specific assembly (in this case WPF), which pretty much makes it impossible to reuse that viewmodel for anything else.
If you wanted to make both WPF, Silverlight, Windows Phone, Windows Store App, etc. clients, you would have no chance of using the same viewmodel for them all, since Windows Phone probably doesn't know what a WPF window is.
Also, unit-testing viewmodels becomes more cumbersome when you have references to actual view elements in there.
So instead of referencing the window directly, you could abstract it away in some kind of view adapter.
If the viewmodel only knows about an interface like this:
public interface IView
{
void Show();
void Close();
}
...each of your clients can create their own implementation of it, and inject it into the viewmodel so it does the right thing on any given client.
The point is that the viewmodel has no knowledge of the actual view. Everything is hidden in the implementation of the interface.
Well, yes your solution is breaking the pattern. Biggest disadvantage is, that you cannot completely test the VM and the logic, which is interfering with the closing of the window. But as always you have to consider, if it's worth the effort to implement a workaround.
So if you really want to stick to MVVM, you could use the solution I posted in the first linked SO post. I copied the essential part of my post in here.
Quote
<Window x:Class="AC.Frontend.Controls.DialogControl.Dialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:DialogControl="clr-namespace:AC.Frontend.Controls.DialogControl"
xmlns:hlp="clr-namespace:AC.Frontend.Helper"
MinHeight="150" MinWidth="300" ResizeMode="NoResize" SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterScreen" Title="{Binding Title}"
hlp:AttachedProperties.DialogResult="{Binding DialogResult}" WindowStyle="ToolWindow" ShowInTaskbar="True"
Language="{Binding UiCulture, Source={StaticResource Strings}}">
<!-- A lot more stuff here -->
</Window>
As you can see, I'm declaring the namespace xmlns:hlp="clr-namespace:AC.Frontend.Helper" first and afterwards the binding hlp:AttachedProperties.DialogResult="{Binding DialogResult}".
[...]
public class AttachedProperties
{
#region DialogResult
public static readonly DependencyProperty DialogResultProperty =
DependencyProperty.RegisterAttached("DialogResult", typeof (bool?), typeof (AttachedProperties), new PropertyMetadata(default(bool?), OnDialogResultChanged));
private static void OnDialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var wnd = d as Window;
if (wnd == null)
return;
wnd.DialogResult = (bool?) e.NewValue;
}
public static bool? GetDialogResult(DependencyObject dp)
{
if (dp == null) throw new ArgumentNullException("dp");
return (bool?)dp.GetValue(DialogResultProperty);
}
public static void SetDialogResult(DependencyObject dp, object value)
{
if (dp == null) throw new ArgumentNullException("dp");
dp.SetValue(DialogResultProperty, value);
}
#endregion
}
/Quote
The only thing you need is a VM like this to make my solution work.
public class WindowVm : ViewModelBase // base class implementing INotifyPropertyChanged
{
private bool? _dialogResult;
public bool? DialogResult
{
get { return _dialogResult; }
set
{
_dialogResult = value;
RaisePropertyChanged(() => DialogResult);
}
}
//... many other properties
}

UI Binding Validation in MVVM

I'm working on converting some code to a more proper MVVM implementation using DataTemplates and am having problems with certain kinds of UI validation.
I've got no problems with validation in the View Models -- IDataErrorInfo is implemented and everything is fine. What I've got a problem with is UI binding errors where they might put letters in a TextBox bound to an int.
Previously, I used :
System.Windows.Controls.Validation.AddErrorHandler(userControl, handler)
... and kept a count of errors added and removed to know whether all the form's data was OK.
But now that I'm doing MVVM I don't have access to the userControl to set up this handler. So I don't really have a hook to get this started.
Is there some sort of global DataTemplateApplied event handler available where I could do something like:
void OnDataTemplateApplied(object data, Control template)
{
if (data is MyViewModelBase)
{
Validation.AddErrorHandler(template, handler);
}
}
Alternatively, maybe I can call AddErrorHandler once in the bootstrapper for the outer Shell window, and then each time the event is fired somehow figure out which ViewModel is powering that particular control?
I know some people like making all VM fields strings and doing lots of type conversion in the VM -- that's not going to be realistic for our system for a variety of reasons.
You might be interested in this answer: https://stackoverflow.com/a/13335971/1094526
The main idea is exactly what you said (subscribe to the error handler). As I understand, the problem is you don't have access to the control from the ViewModel, but it isn't hard to solve
In a project I'm working, I exposed two methods from my ViewModel: AddUIError and RemoveUIError. I create an event handler in my View and there I cast the DataContext to the type of my ViewModel and call AddUIError or RemoveUIError depending on what happened.
I am using DataTemplates to associate a View with a ViewModel, so when the template is applied, the DataContext is automatically set to the ViewModel. If you want, you can store your ViewModel in a private field (in the View) and update the reference each time the DataContext changed (there is a DataContextChanged event)
If this will be done in multiple ViewModels, you can put both methods (AddUIError and RemoveUIError) in a class like ViewModelBase and move the ValidationError event handling to a Behavior and use it in each view.
More info about the behavior part:
The Behavior class is part of the Expression Blend SDK, so you will need it if you want to follow this way.
Behaviors are useful to attach some common functionality to many components without creating derived classes, for example.
First, we need to define the AddUIError and RemoveUIError in a class named ViewModelBase (which is, of course, the base class for all other ViewModels):
class ViewModelBase {
public void AddUIError(...) {/* Details ommitted */ }
public void RemoveUIError(...) {/* Details ommitted */ }
}
Then, create a Behavior by subclassing Behavior. We use FrameworkElement as the template argument so this behavior can be attached to any FrameworkElement (or derived class) instance:
class NotifyDataErrorsBehavior : Behavior<FrameworkElement>
{
// Called when the the Behavior is attached
protected override void OnAttached()
{
base.OnAttached();
// Initialize the handler for the Validation Error Event
_handler = new RoutedEventHandler(OnValidationRaised);
// Add the handler to the event from the element which is attaching this behavior
AssociatedObject.AddHandler(System.Windows.Controls.Validation.ErrorEvent, _handler);
}
protected override void OnDetaching()
{
base.OnDetaching();
// Remove the event handler from the associated object
AssociatedObject.RemoveHandler(System.Windows.Controls.Validation.ErrorEvent, _handler);
}
private RoutedEventHandler _handler = null;
private void OnValidationRaised(object sender, RoutedEventArgs e)
{
var args = (System.Windows.Controls.ValidationErrorEventArgs)e;
ViewModelBase viewModel = AssociatedObject.DataContext as ViewModelBase;
if (viewModel != null)
{
// You can add only Exception validation errors if you want..
if (args.Action == ValidationErrorEventAction.Added)
viewModel.AddUIValidationError(...);
else if (args.Action == ValidationErrorEventAction.Removed)
viewModel.RemoveUIValidationError(...);
else
throw new NotSupportedException("ValidationErrorEventAction has changed");
}
}
}
And finally just use it in XAML:
1. Add a reference to the namespace where NotifyDataErrorsBehavior is located, and also a reference to System.Windows.Interactivity namespace (from Expression Blend SDK):
<UserControl
...
xmlns:behavior="clr-namespace:MyApp.Behaviors"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
...
>
2. Add the behavior (at the same level as the content of your UserControl:
<i:Interaction.Behaviors>
<behavior:NotifyDataErrorsBehavior/>
</i:Interaction.Behaviors>
Ex:
<UserControl
...
xmlns:behavior="clr-namespace:MyApp.Behaviors"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
...
>
<i:Interaction.Behaviors>
<behavior:NotifyDataErrorsBehavior/>
</i:Interaction.Behaviors>
<Grid>
...
</Grid>
</UserControl>

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.

Binding a ContentControl to a deep path in WPF

The application I'm currently writing is using MVVM with the ViewModel-first pattern. I have XAML similar to the following:
<ContentControl Content="{Binding FooViewModel.BarViewModel.View, Mode=OneWay}"/>
Every VM is a DependencyObject. Every property is a DependencyProperty. Depending upon the state of the application, the value of the BarViewModel property of the FooViewModel can change, thus changing the value of the View property. Unfortunately when this happens, the new view is not displayed, and the old one remains.
This is extremely frustrating. I thought that if any part of a path expression changed, the binding would update, but that doesn't appear to be the case. When I've used shallower path expressions, such as FooViewModel.View and I've changed the value of the FooViewModel property, that has updated the ContentControl to which it's bound, but not in this case.
If your solution is that I abandon ViewModel-first, that is not an option, though I appreciate your advice. I must get this working as is.
CLARIFICATION
This is a question about data binding, and not about MVVM or how to implement it. You can safely ignore the MVVM aspects of this if it helps you to think about the problem, or if you have a different idea about how MVVM should be implemented. This is a large, existing project in which the MVVM design pattern cannot be changed. (It is far too late for that.)
So, with that said, the correct question to be answering is the following:
Given a binding path expression in which every element is a DependencyProperty and the final property is a view bound to a ContentControl, why does a change in a property in the middle of the path not cause the binding to update?
Although I would expect this to work, there are several problems with your approach.
Firstly, your view models should not use DependencyObject or DependencyProperty, this ties them in to WPF. They should instead implement INotifyPropertyChanged. This makes your view models reusable in other presentation technologies such as Silverlight.
Secondly, your view models shouldn't have references to your views, so you shouldn't require a View property on your view models.
I would seriously consider using an MVVM framework for view composition - Caliburn.Micro, for example, makes view model first development extremely straightforward, and already provides a view model base class which implements INotifyPropertyChanged, and a mechanism for building view compositions with conventions.
I.e. you can have a conductor view model which has an ActiveItem property, and you simply place a ContentControl on your view with the same name as the property:
<ContentControl x:Name="ActiveItem" />
You can use the ActivateItem() method to change the current active item.
Caliburn.Micro also has a host of other features, such as being able to place a Button control with x:Name="Save" on your view, and your Save method on your view model will automatically be invoked when the button is clicked.
Every VM is a DependencyObject. Every property is a
DependencyProperty.
why? a viewmodel should be a simple class with INotifyPropertyChanged and the Properties should be simple properties.
and if you want your different viewmodel be rendered in a different way - you should use DataTemplate.
<Window>
<Window.Resources>
<DataTemplate DataType="{x:Type local:MyViewModelA}>
<MyViewA/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:MyViewModelB}>
<MyViewB/>
</DataTemplate>
</Windows.Resources>
<Grid>
<ContentControl Content="{Binding MyActualVM}"/>
</Grid>
</Window>
EDIT: btw you always bind to the last Property: FooViewModel.BarViewModel.View --> so the INotifyPropertyChanged (if raised) just work for the .View
EDIT2: another approach could be to get the BindingExpression of your content control and call.
System.Windows.Data.BindingExpression expr = //get it from your contentcontrol
expr.UpdateTarget();
EDIT3: and a simple mvvm way - just use INotifyPropertyChanged
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.MyFooVM = new FooVM();
this.MyFooVM.MyBarVM = new BarVM(){View = "erster"};
this.DataContext = this;
}
public FooVM MyFooVM { get; set; }
private void Button_Click(object sender, RoutedEventArgs e)
{
this.MyFooVM.MyBarVM = new BarVM(){View = "zweiter"};
}
}
public class INPC : INotifyPropertyChanged
{
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropChanged(string property)
{
var handler = PropertyChanged;
if(handler != null)
handler(this, new PropertyChangedEventArgs(property));
}
#endregion
}
public class FooVM:INPC
{
private BarVM _myBarVm;
public BarVM MyBarVM
{
get { return _myBarVm; }
set { _myBarVm = value;OnPropChanged("MyBarVM"); }
}
}
public class BarVM : INPC
{
private string _view;
public string View
{
get { return _view; }
set { _view = value;OnPropChanged("View"); }
}
}

When to use a WPF Dependency Property versus INotifyPropertyChanged

Do folks have any guidance on when a simple .NET property that fires INotifyPropertyChanged.PropertyChanged is sufficient in a view model? Then when do you want to move up to a full blown dependency property? Or are the DPs intended primarily for views?
There are a few approaches:
1. The dependency property
While you using the dependency property it makes the most sense in elements-classes that have a visual appearance (UIElements).
Pros:
WPF do the logic stuff for you
Some mechanism like animation use only dependency property
'Fits' ViewModel style
Cons:
You need to derive form DependencyObject
A bit awkward for simple stuff
Sample:
public static class StoryBoardHelper
{
public static DependencyObject GetTarget(Timeline timeline)
{
if (timeline == null)
throw new ArgumentNullException("timeline");
return timeline.GetValue(TargetProperty) as DependencyObject;
}
public static void SetTarget(Timeline timeline, DependencyObject value)
{
if (timeline == null)
throw new ArgumentNullException("timeline");
timeline.SetValue(TargetProperty, value);
}
public static readonly DependencyProperty TargetProperty =
DependencyProperty.RegisterAttached(
"Target",
typeof(DependencyObject),
typeof(Timeline),
new PropertyMetadata(null, OnTargetPropertyChanged));
private static void OnTargetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Storyboard.SetTarget(d as Timeline, e.NewValue as DependencyObject);
}
}
2. The System.ComponentModel.INotifyPropertyChanged
Usually, when creating a data object, you’ll use this approach. It is simple and neat solution for Data-like stuff.
Pros and Cons - complementary to 1. You need to to implement only one event (PropertyChanged).
Sample:
public class Student : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
}
private string name;
public string Name;
{
get { return name; }
set {
name = value;
OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
3.PropertyNameChanged
Rising an event for each property with specified name(f.e. NameChanged). Event must have this name and it is up to you to handle/rise them. Similar approach as 2.
4. Get the binding
Using the FrameworkElement.GetBindingExpression() you can get the BindingExpression object
and call BindingExpression.UpdateTarget() to refresh.
First and second are the most likely depending what is your goal.
All in all, it is Visual vs Data.
As far as I know, DependencyProperty is only required when you need
PropertyValue inheritence
you need to allow the property to be set in Style setters
Use animation for the property
etc.
These features will not be available with normal properties.
DependencyProperty is required if you want to allow a binding to be set on the property. Usually this is for custom UIElements you create. You want to allow people to be able to bind data to your UIElements.
<local:MyUIElement MyProperty={Binding Path=SomethingToBindTo} />
To do this requires that MyProperty is a dependancy property
The main problem I see with INotifyPropertyChanged is if you viewmodel is complex containing many nested types it appears that you have to bubble the PropertyChanged event up through the hierarchy.
As the other answers have already said enough about when to create dependency property. i.e.
PropertyValue inheritence
you need to use binding on a property
Use animation for the property
The one more perspective/question on this is "In a WPF application is makes sense to create dependency properties in a control cause they are likely to change during user interaction like Height,width, text,content, background etc but what about other classes like Behaviors Classes(Non UI classes). Do properties in those classes need to be a dependency property?"
I won't say for very absolute or emphasis on some set of rules here but you should create your properties as DP. As from design perspective if a property is DP it's always in default form of WPF to use/bind.i.e.
As a DP is much more fast/natural in reflecting changes compare to a normal CLR property.
A DP has validation mechanism to validate the value assigned and a default structure to revert the value.
A DP has Coerce value callback to control the limits of property.
A DP has meta data associated with it unlike CLR property.
In terms of practices I've seen people doing many mistakes in nested bindings and then raising changes these kind of faults doesn't happen with a DP cause of it's design and compatibility of raising change itself. So with a little extra syntax you put a flexibility/performance/ easeness to your application. So go for it wherever affordable.
Still can't say sure for ViewModel classes/other helper classes. will update the answer if found convincing reasons in future.
Just a post worth reading on this topic

Resources