Am I OK with a Clean <project Name> in Visual Studio 12? - wpf

I am Performing a Tutorial I found in Expression Blend 4 for connecting to a SQL Server with WPF. After the final steps in VS12 when I do a build I get the following error.
Error 1 The type or namespace name 'DelegateCommand' could not be found (are you missing a using directive or an assembly reference?)
Error 2 The type or namespace name 'DelegateCommand' could not be found (are you missing a using directive or an assembly reference?)
When I do a Clean I do not get these errors.
My Target is .net 4.5 I also tried 4.0
My code That is erroring looks Like this. I bolded the two erroring lines. this is a file called Class1.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace AWADataSource
{
public class ProductPhotosCollection
{
**private DelegateCommand getDataCommand;
public DelegateCommand GetDataCommand { get { return getDataCommand; } }**
public ProductPhotosCollection()
{
getDataCommand = new DelegateCommand(delegate() { GetData(); });
}
public ObservableCollection<ProductPhoto> ProductPhotos
{ get { return this.productPhotos; } }
private ObservableCollection<ProductPhoto> productPhotos =
new ObservableCollection<ProductPhoto>();
private void GetData()
{
ProductPhotosTableAdapters.ProductPhotoTableAdapter da =
new ProductPhotosTableAdapters.ProductPhotoTableAdapter();
ProductPhotos.ProductPhotoDataTable dt = da.GetData();
productPhotos.Clear();
foreach (ProductPhotos.ProductPhotoRow row in dt)
{
productPhotos.Add(new ProductPhoto(
row.ProductPhotoID,
row.ThumbNailPhoto,
row.LargePhoto,
row.ModifiedDate));
}
}
}
public class ProductPhoto
{
// Public Accessors to the private properties.
public int ID { get { return id; } }
public ImageSource ThumbNailPhoto { get { return thumbNailPhoto; } }
public ImageSource LargePhoto { get { return largePhoto; } }
public DateTime ModifiedDate { get { return modifiedDate; } }
// Constructor.
public ProductPhoto(int id, byte[] thumbNailPhoto, byte[] largePhoto,
DateTime modifiedDate)
{
this.id = id;
this.thumbNailPhoto = ByteArrayToImageSource(thumbNailPhoto);
this.largePhoto = ByteArrayToImageSource(largePhoto);
this.modifiedDate = modifiedDate;
}
// Private properties.
private int id;
private ImageSource thumbNailPhoto;
private ImageSource largePhoto;
private DateTime modifiedDate;
// Supporting method.
private ImageSource ByteArrayToImageSource(byte[] data)
{
BitmapImage image = null;
if (null != data)
{
image = new BitmapImage();
image.BeginInit();
image.StreamSource = new System.IO.MemoryStream(data);
image.EndInit();
}
return image;
}
}
}
and my other file is called DelegateCommand.cs which was pretty much a copy and paist.
namespace AWDataSource
{
using System;
using System.Windows.Input;
///
/// DelegateCommand is a simplified version of ICommand in WPF. You can wrap one of these around any method,
/// and thus bind any command on any WPF object to your method.
///
/// DelegateCommand also supports an IsEnabled property that you can use to turn the command on and off.
///
public sealed class DelegateCommand : ICommand
{
// Remember the method so that it can be called at the right time.
private SimpleEventHandler handler;
// Maintain the enabled state.
private bool isEnabled = true;
// Type signature of the method that DelegateCommand works with - returns void, no arguments.
public delegate void SimpleEventHandler();
// Simple constructor: Pass in the method that needs to be called when the command executes.
public DelegateCommand(SimpleEventHandler handler)
{
this.handler = handler;
}
#region ICommand implementation
// Executing the command is as simple as calling the method.
void ICommand.Execute(object arg)
{
this.handler();
}
// Saying whether the command can be executed.
bool ICommand.CanExecute(object arg)
{
return this.IsEnabled;
}
// This is the event that the command architecture of WPF listens to so it knows when to update
// the UI on command enable/disable.
public event EventHandler CanExecuteChanged;
#endregion
// Public visibility of the isEnabled flag - note that when it is set, the event must be raised
// so that WPF knows to update any UI that uses this command.
public bool IsEnabled
{
get { return this.isEnabled; }
set
{
this.isEnabled = value;
this.OnCanExecuteChanged();
}
}
// Simple event propagation that makes sure that someone is listening to the event before raising it.
private void OnCanExecuteChanged()
{
if (this.CanExecuteChanged != null)
{
this.CanExecuteChanged(this, EventArgs.Empty);
}
}
}
}

ProductPhotosCollection is in namespace AWADataSource while DelegateCommand is in AWDataSource.
Probably a typo, but you either need to put them in the same namespace, or use a using to import the AWDataSource namespace into ProductPhotosCollection (or in your case "Class1.cs")

Related

How to display new modal form in ReactiveUI 6.5

I am one of a team of developers currently maintaining a large suite of applications written using the WinForms UI.
In order to improve testability of our applications, we are wanting to move to an MVVM style, to separate the UI from the business logic. However, we need to keep using the WinForms UI, to minimize impact on our users as they work with different applications in the suite.
In trialing ReactiveUI, I have got a handle on how to bind form controls and commands to my view model, but cannot find documentation or examples on how to pop up a modal form to ask for or display additional information. For example these documentation pages on routing mention every supported UI framework except WinForms: http://docs.reactiveui.net/en/user-guide/routing/index.html, https://github.com/reactiveui/ReactiveUI/blob/docs/docs/basics/routing.md
Unfortunately, the ReactiveUI "good examples page" does not appear to have any WinForms-based examples, and all the other ReactiveUI / WinForms examples I can find using Google are only a single form.
I definitely want to keep forms/views out of the view model to maintain testability.
I believe the right way is to have a ReactiveCommand that is triggered by some user action in the view (such as clicking a button, selecting a menu item), but:
What should the command do?
Should it use Routing even though WinForms is not mentioned in the documentation? If yes, how is Routing done in a WinForms application?
How would the command/routing request the new form gets shown modally?
For simple messages and yes/no answers, I would look at Wayne Maurer's example for using UserError. I've used his example in Winform projects.
For something more complex, I was having the same difficulties finding any Winforms examples for routing. My google searches finally landed me in the source code for ReactiveUI.Winforms, where I discovered that Paul already has a UserControl for Winforms that will host routed UserControl views. It's called RoutedControlHost.
Using that code, I hacked something together that will show modal forms. I'm sure this isn't the best way to do it, but it might give you ideas.
RoutedModalHost
using Microsoft.Win32.SafeHandles;
using ReactiveUI;
using System;
using System.ComponentModel;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ReactiveUI_Test_Routing
{
public class RoutedModalHost : ReactiveObject, IDisposable
{
readonly CompositeDisposable disposables = new CompositeDisposable();
RoutingState _Router;
IObservable<string> viewContractObservable;
public RoutedModalHost()
{
this.ViewContractObservable = Observable.Return(default(string));
var vmAndContract =
this.WhenAnyObservable(x => x.Router.CurrentViewModel)
.CombineLatest(this.WhenAnyObservable(x => x.ViewContractObservable),
(vm, contract) => new { ViewModel = vm, Contract = contract });
Form viewLastAdded = null;
this.disposables.Add(vmAndContract.Subscribe(x => {
if (viewLastAdded != null)
{
viewLastAdded.Dispose();
}
if (x.ViewModel == null)
{
return;
}
IViewLocator viewLocator = this.ViewLocator ?? ReactiveUI.ViewLocator.Current;
IViewFor view = viewLocator.ResolveView(x.ViewModel, x.Contract);
view.ViewModel = x.ViewModel;
viewLastAdded = (Form)view;
viewLastAdded.ShowDialog();
}, RxApp.DefaultExceptionHandler.OnNext));
}
[Category("ReactiveUI")]
[Description("The router.")]
public RoutingState Router
{
get { return this._Router; }
set { this.RaiseAndSetIfChanged(ref this._Router, value); }
}
[Browsable(false)]
public IObservable<string> ViewContractObservable
{
get { return this.viewContractObservable; }
set { this.RaiseAndSetIfChanged(ref this.viewContractObservable, value); }
}
[Browsable(false)]
public IViewLocator ViewLocator { get; set; }
bool disposed = false;
SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
handle.Dispose();
// Free any other managed objects here.
//
this.disposables.Dispose();
}
// Free any unmanaged objects here.
//
disposed = true;
}
}
}
MainViewModel
using ReactiveUI;
using System.Reactive.Linq;
using System;
namespace ReactiveUI_Test_Routing
{
public class MainViewModel : ReactiveObject, IScreen
{
public RoutingState Router { get; private set; }
public ReactiveCommand<object> ShowTestModalForm { get; protected set; }
public MainViewModel(RoutingState modalRouter)
{
Router = modalRouter;
ShowTestModalForm = ReactiveCommand.Create();
ShowTestModalForm.Subscribe(x => Router.Navigate.Execute(new TestModalFormViewModel(this)));
}
}
}
MainView
using System.Windows.Forms;
using Splat;
using ReactiveUI;
namespace ReactiveUI_Test_Routing
{
public partial class MainView : Form, IViewFor<MainViewModel>
{
public MainView()
{
InitializeComponent();
IMutableDependencyResolver dependencyResolver = Locator.CurrentMutable;
dependencyResolver.Register(() => new TestModalFormView(), typeof(IViewFor<TestModalFormViewModel>));
RoutingState router = new RoutingState();
RoutedModalHost modalHost = new RoutedModalHost();
modalHost.Router = router;
this.BindCommand(ViewModel, vm => vm.ShowTestModalForm, v => v.ShowTestModalForm);
ViewModel = new MainViewModel(router);
}
public MainViewModel ViewModel { get; set; }
object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = (MainViewModel)value; }
}
}
}
TestModalFormViewModel
using ReactiveUI;
namespace ReactiveUI_Test_Routing
{
public class TestModalFormViewModel : ReactiveObject, IRoutableViewModel
{
public IScreen HostScreen { get; protected set; }
public string UrlPathSegment { get { return "ModalForm"; } }
public TestModalFormViewModel(IScreen screen)
{
HostScreen = screen;
}
}
}

How to inject an action into a command using Ninject?

Actually exploring the Command Pattern and finds it pretty interesting. I'm writing a WPF Windows App following the MVVM Architectural Pattern.
I've begun with these post which explain the basics.
Basic MVVM and ICommand usuage example
Simplify Distributed System Design Using the Command Pattern, MSMQ, and .NET
Now that I was able to break user actions into commands, I thought this could be great to inject the commands that I want. I noticed that the commands are found into the ViewModel in the first referenced article, So I thought that would be great if I could use them along Ninject and actually inject my command into my view model using a binding that would look like the following:
kernel
.Bind<ICommand>()
.To<RelayCommand>()
.WithConstructorArgument("execute", new Action<object>(???));
But then, what to put in here ???. The expected answer is a method. Great! I just need a method to be put in there.
Because the first article simply initialize its commands within the ViewModel constructor, it is easy to say what method should be executed on the command execute call.
But from within the CompositionRoot? This is no place to put a method that will do anything else than bind types together through whatever DI container you're using!
So now, I've come across the Interceptor Pattern using Ninject Extensions. This looks like it could suits my requirements, and there is a bit of confusion here, if I may say. Not that the articles are confusing, they're not. I'm confused!
Using Ninject.Extensions.Interception Part 1 : The Basics
Using Ninject.Extensions.Interception Part 2 : Working With Interceptors
Also, there is this answer from BatteryBackupUnit who always sets great answers.
Ninject - How to implement Command Pattern with Ninject?
But now, I can't see how to glue it all up together! Humbly, I'm lost.
So here's my code so far.
RelayCommand
public class RelayCommand : ICommand {
public RelayCommand(Action<object> methodToExecute, Predicate<object> canExecute) {
if(methodToExecute == null)
throw new ArgumentNullException("methodToExecute");
if(canExecute == null)
throw new ArgumentNullException("canExecute");
this.canExecute = canExecute;
this.methodToExecute = methodToExecute;
}
public bool CanExecute(object parameter) {
return canExecute != null && canExecute(parameter);
}
public event EventHandler CanExecuteChanged {
add {
CommandManager.RequerySuggested += value;
canExecuteChanged += value;
}
remove {
CommandManager.RequerySuggested -= value;
canExecuteChanged -= value;
}
}
public static bool DefaultCanExecute(object parameter) { return true; }
public void Execute(object parameter) { methodToExecute(parameter); }
public void OnCanExecuteChanged() {
var handler = canExecuteChanged;
if(handler != null) handler(this, EventArgs.Empty);
}
public void Destroy() {
canExecute = _ => false;
methodToExecute = _ => { return; };
}
private Predicate<object> canExecute;
private Action<object> methodToExecute;
private event EventHandler canExecuteChanged;
}
CategoriesManagementViewModel
public class CategoriesManagementViewModel : ViewModel<IList<Category>> {
public CategoriesManagementViewModel(IList<Category> categories
, ICommand changeCommand
, ICommand createCommand
, ICommand deleteCommand) : base(categories) {
if(changeCommand == null)
throw new ArgumentNullException("changeCommand");
if(createCommand == null)
throw new ArgumentNullException("createCommand");
if(deleteCommand == null)
throw new ArgumentNullException("deleteCommand");
this.changeCommand = changeCommand;
this.createCommand = createCommand;
this.deleteCommand = deleteCommand;
}
public ICommand ChangeCommand { get { return changeCommand; } }
public ICommand CreateCommand { get { return createCommand; } }
public ICommand DeleteCommand { get { return deleteCommand; } }
private readonly ICommand changeCommand;
private readonly ICommand createCommand;
private readonly ICommand deleteCommand;
}
I wonder, would it be better off using Property Injection, though I tend not to use it all?
Let's say I have CategoriesManagementView that calls another window, let's say CreateCategoryView.Show(), and then the CreateCategoryView takes over until the user is back to the management window.
The Create Command then needs to call CreateCategoryView.Show(), and that is what I tried from within the CompositionRoot.
CompositionRoot
public class CompositionRoot {
public CompositionRoot(IKernel kernel) {
if(kernel == null) throw new ArgumentNullException("kernel");
this.kernel = kernel;
}
//
// Unrelated code suppressed for simplicity sake.
//
public IKernel ComposeObjectGraph() {
BindCommandsByConvention();
return kernel;
}
private void BindCommandsByConvention() {
//
// This is where I'm lost. I can't see any way to tell Ninject
// what I want it to inject into my RelayCommand class constructor.
//
kernel
.Bind<ICommand>()
.To<RelayCommand>()
.WithConstructorArgument("methodToExecute", new Action<object>());
//
// I have also tried:
//
kernel
.Bind<ICommand>()
.ToConstructor(ctx =>
new RelayCommand(new Action<object>(
ctx.Context.Kernel
.Get<ICreateCategoryView>().ShowSelf()), true);
//
// And this would complain that there is no implicit conversion
// between void and Action and so forth.
//
}
private readonly IKernel kernel;
}
Perhaps I am overcomplicating things, that is generally what happends when one gets confused. =)
I just wonder whether the Ninject Interception Extension could be the right tool for the job, and how to use it effectively?
I created a simple example of a command interacting with an injected service. might not compile since i'm going from memory. Maybe this can help you.
public class TestViewModel
{
private readonly IAuthenticationService _authenticationService;
public DelegateCommand SignInCommand { get; private set; }
public TestViewModel(IAuthenticationService authenticationService) //Inject auth service
{
_authenticationService = authenticationService
SignInCommand = new DelegateCommand(OnSignInRequest)
}
private void OnSignInRequest(Action<bool> isSuccessCallback)
{
var isSuccess = _authenticationService.SignIn();
isSuccessCallback(isSuccess);
}
}
}

How to fix an error in the WPF design with custom control

I am attempting to create a region control that does the following trick
<wgc:RegionContentControl Region="HotDog">
<Label>Foo</Label>
<Label>Bar</Label>
</wgc:RegionContentControl>
<wgc:RegionControl Region="HotDog">
</wgc:RegionControl>
At run time and design time the controls defined in RegionContentControl
will get appended to RegionControl. I can use this to inject stuff into
status bars for example.
Anyway at runtime it works fine and sometimes in the designer it work.
However sometimes in the designer I get an error that
Element already has a logical parent. It must be detached from the
old parent before it is attached to the new one.
My code implementing the above pattern is below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace My.Controls
{
public class RegionMessage {
public enum RegionAction {
Add,
Remove,
}
public string Region { get; set; }
public List<Control> Controls { get; set; }
public RegionAction Action { get; set; }
}
public class RegionControl : ItemsControl
{
public RegionControl()
{
ReactiveUI
.MessageBus.Current
.Listen<RegionMessage>()
.Subscribe(HandleRegionMessage);
}
public string Region
{
get { return (string)GetValue(RegionProperty); }
set { SetValue(RegionProperty, value); }
}
public static readonly DependencyProperty RegionProperty =
DependencyProperty.Register("Region", typeof(string), typeof(RegionControl), new PropertyMetadata(""));
private void HandleRegionMessage(RegionMessage obj)
{
if (obj.Region!=Region)
{
return;
}
if (obj.Action==RegionMessage.RegionAction.Add)
{
foreach (var item in obj.Controls)
{
this.Items.Add(item);
}
}
else
{
foreach (var item in obj.Controls)
{
this.Items.Remove(item);
}
}
}
}
[ContentProperty("Children")]
public class RegionContentControl : Control
{
static RegionContentControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(RegionContentControl), new FrameworkPropertyMetadata(typeof(RegionContentControl)));
}
public static readonly DependencyProperty ChildrenProperty =
DependencyProperty.Register("Children", typeof(List<Control>), typeof(RegionContentControl), new PropertyMetadata(new List<Control>()));
public List<Control> Children
{
get { return (List<Control>)GetValue(ChildrenProperty); }
set { SetValue(ChildrenProperty, value); }
}
public string Region
{
get { return (string)GetValue(RegionProperty); }
set { SetValue(RegionProperty, value); }
}
// Using a DependencyProperty as the backing store for Region. This enables animation, styling, binding, etc...
public static readonly DependencyProperty RegionProperty =
DependencyProperty.Register("Region", typeof(string), typeof(RegionContentControl), new PropertyMetadata(""));
public RegionContentControl()
{
this.LoadedObserver().Subscribe(Loaded);
}
private void Loaded(System.Reactive.EventPattern<RoutedEventArgs> obj)
{
ReactiveUI.MessageBus.Current.SendMessage(new RegionMessage()
{
Action = RegionMessage.RegionAction.Add
,
Controls = Children
,
Region = Region
});
}
}
}
I am sure that my problem involves that the controls still think they are attached to the RegionContentControl but I'm not sure how to detach them correctly. Any suggestions?
Removing the items from Children before broadcasting does the trick
List<Control> _HiddenChildren;
private void Loaded(System.Reactive.EventPattern<RoutedEventArgs> obj)
{
if (_HiddenChildren==null)
{
_HiddenChildren = Children;
this.Children = new List<Control>();
}
ReactiveUI.MessageBus.Current.SendMessage(new RegionMessage()
{ Action = RegionMessage.RegionAction.Add
, Controls = _HiddenChildren
, Region = Region
});
}

Winforms databinding and validation, why is datasource updated when validation fails?

The code below illustrates some unexpected (for me!) behaviour when combining data binding and validation in winforms. Can anyone tell me how I can prevent the datasource from being updated when validation fails?
Many thanks.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ValidationBug
{
/// <summary>
/// This illustrates some unexpected behaviour with winforms validation and binding
///
/// To reproduce: Run the program, enter a value into the textbox, click the X to close the form.
///
/// Expected behaviour: validation of textbox fails so data source is not updated.
///
/// Observed behaviour: data source is updated.
/// </summary>
public class Form1 : Form
{
private class Data
{
private string _field;
public string Field
{
get { return _field; }
set
{
// this should never be called, but it is.
_field = value;
}
}
}
private System.ComponentModel.IContainer components = null;
public Form1()
{
this.Load += new System.EventHandler(this.Form1_Load);
}
private void Form1_Load(object sender, EventArgs e)
{
AutoValidate = System.Windows.Forms.AutoValidate.EnablePreventFocusChange;
var txt = new TextBox();
// validation always fails.
txt.Validating += new CancelEventHandler((s, ev) => ev.Cancel = true);
Controls.Add(txt);
var data = new Data();
this.components = new System.ComponentModel.Container();
BindingSource bs = new BindingSource(this.components);
bs.DataSource = typeof(Data);
// only update datasource on succesful validation.
txt.DataBindings.Add(new Binding("Text", data, "Field", false, DataSourceUpdateMode.OnValidation));
}
}
}
I tend to "brute force" my code - could you set an initial value to your private string _field, perhaps in a constructor?
Also, are you sure that setting your CancelEventHandler's Cancel property to TRUE marks your data as invalid?
You may even want to add a private bool _valid field to your Data class that only returns values if it is valid.
private class Data
{
private bool _valid;
private string _field;
public Data()
{
_field = null;
_valid = false;
}
public string Field
{
get
{
if (_valid)
{
return _field;
} else {
return null;
}
set
{
// this should never be called, but it is.
_field = value;
_valid = !String.IsNullOrEmpty(_field);
}
}
}
Just some ideas to look into.

WPF custom DependencyProperty notify changes

I have a class called MyComponent and it has a DependencyProperty caled BackgroundProperty.
public class MyComponent
{
public MyBackground Background
{
get { return (MyBackground)GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}
public static readonly DependencyProperty BackgroundProperty =
DependencyProperty.Register("Background", typeof(MyBackground),
typeof(MyComponent), new FrameworkPropertyMetadata(default(MyBackground), new PropertyChangedCallback(OnPropertyChanged)));
}
MyBackground is a class that derives from DependencyObject and it has some DependencyProperties.
public class MyBackground : DependencyObject
{
public Color BaseColor
{
set { SetValue(BaseColorProperty, value); }
get { return (Color)GetValue(BaseColorProperty); }
}
public static readonly DependencyProperty BaseColorProperty =
DependencyProperty.Register("BaseColor", typeof(Color),
typeof(MyBackground ), new UIPropertyMetadata(Colors.White));
[...]
}
Now, what I want is when a property from MyBackground is changed, MyComponent to be notified that MyBackground has changed and the PropertyChangedCallback named OnPropertyChanged to be called.
Bear with me for a second because it appears that you are trying to go against the grain of WPF. Since it seems you are writing code related to display logic, the typical method for getting related DependencyObjects to interact with one another is through bindings.
If, for example, MyComponent is a control of some sort and it uses the Background property in its ControlTemplate, you would use a TemplateBinding that references the Background property and any important sub-properties.
Since 1) you probably already know that and 2) you either aren't using templates or don't have them available, you can set up a binding in code in order to react to changes in to the Background property. If you provide more detail about what your OnPropertyChanged method does I can provide some sample code.
One way to do what you describe would be to derive from Freezable instead of DependencyObject. When a property of a Freezable changes the PropertyChangedCallback for any DO referencing that Freezable will be invoked so the callback for the Background property of your MyComponent. In that case the e.OldValue and e.NewValue will be the same reference. Internally WPF has some flag on the event args that indicates that it is a subobject change.
This is what the framework does for things like brushes so that an element can be invalidated if say the Color property of a SolidColorBrush is changed. If an object will never be changed (or you want to make it thread safe) then one can freezing the object (i.e. making it immutable).
BTW I would probably avoid using Background as the name of the property. Most developers will assume that is of type Brush as that is what the framework uses for that named property on several of its elements (e.g. control, border).
Sounds like you want to use a DependencyPropertyDescriptor and AddValueChanged.
Here's an article on it: http://www.codeproject.com/Articles/34741/Change-Notification-for-Dependency-Properties.aspx
..and possibly a better implementation: http://agsmith.wordpress.com/2008/04/07/propertydescriptor-addvaluechanged-alternative/
Here's a small static class of extension methods I wrote for WPF -- it allows you to register an EventHandler or an Action callback for the changing of any DependencyProperty on any DependencyObject. No changes to the dependency object are necessary.
It also prevents recursion (i.e. if you change that same property during the callback, etc..)
It takes advantage of the DependencyPropertyDescriptor that #ScottBilas linked to.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
namespace BrainSlugs83.Writes.Too.Much.Code
{
public static class WpfExtensions
{
public static void OnPropertyChanged<T>(this T obj, DependencyProperty prop, Action<T> callback) where T : DependencyObject
{
if (callback != null)
{
obj.OnPropertyChanged(prop, new EventHandler((o, e) =>
{
callback((T)o);
}));
}
}
public static void OnPropertyChanged<T>(this T obj, DependencyProperty prop, EventHandler handler) where T : DependencyObject
{
var descriptor = DependencyPropertyDescriptor.FromProperty(prop, typeof(T));
descriptor.AddValueChanged(obj, new EventHandler((o, e) =>
{
if (handler != null)
{
if (o == null) { handler(o, e); }
else
{
lock (PreventRecursions)
{
if (IsRecursing(obj, prop)) { return; }
SetIsRecursing(obj, prop, true);
}
try
{
handler(o, e);
}
finally
{
SetIsRecursing(obj, prop, false);
}
}
}
}));
}
#region OnPropertyChanged Recursion Prevention
private static readonly Dictionary<object, List<DependencyProperty>> PreventRecursions = new Dictionary<object, List<DependencyProperty>>();
private static bool IsRecursing(object obj, DependencyProperty prop)
{
lock (PreventRecursions)
{
List<DependencyProperty> propList = null;
if (PreventRecursions.ContainsKey(obj))
{
propList = PreventRecursions[obj];
}
return propList == null ? false : propList.Contains(prop);
}
}
private static void SetIsRecursing(object obj, DependencyProperty prop, bool value)
{
lock (PreventRecursions)
{
List<DependencyProperty> propList = null;
if (PreventRecursions.ContainsKey(obj))
{
propList = PreventRecursions[obj];
}
if (propList == null)
{
if (!value) { return; }
propList = PreventRecursions[obj] = new List<DependencyProperty>();
}
if (value)
{
if (!propList.Contains(prop))
{
propList.Add(prop);
}
}
else
{
while (propList.Contains(prop))
{
propList.Remove(prop);
}
if (!propList.Any())
{
propList = PreventRecursions[obj] = null;
}
}
}
}
#endregion
public static bool IsInDesignMode(this DependencyObject obj)
{
try
{
return DesignerProperties.GetIsInDesignMode(obj);
}
catch { /* do nothing */ }
return false;
}
}
}

Resources