« Posts under WPF

WPF/MVVM Hack: ValueChangedEventManager

Anyone that has had extensive experience with WPF and has attempted MVVM knows it’s not perfect.  Over the years I’ve attempted many things in an attempt to find the mythical answer to all things WPF data binding.  Have I found the solution?  Not really, but I found something that makes me feel like it would be a small piece of the perfect solution.

The perfect solution to WPF data binding issues?

  1. It would be a small, nearly invisible framework, that largely works behind the scenes to keep the data and the UI in sync.
  2. Users could bind a view model to an underlying object.  Users could bind the underlying object elsewhere.  A change in either location would update the other.  Also, any other view model of the same object would also be updated.
  3. No modifications need ever be required to the “business object”.  By which I mean, my business objects should not have to implement the INotifyPropertyChanged interface.
  4. If I need to replace some portion of functionality that is exposed to the UI I should be able to do so, without requiring that I mindlessly create wrappers for everything else.
  5. WPF needs a general solution to the problem of state persistence in-between refreshes.  Example, the treeview suffers from this, for anything but the simplest of bindings where you just so happen to use an ObservableCollection.  Otherwise your left creating viewmodels that create other viewmodels that maintain selection and expansion knowledge.

So what is in this post?

I’m sure the list could be much longer, but lets move on.  So how much of this will I address today?  Just #1 and #2.

The Exposition

While working on an XNA hobby project. I started making a little level editor and decided to mostly use WPF, but kept the Windows Forms PropertyGrid for editing objects.  All the objects I’m working with are designed to be fast.  So you can forget about adding property changed events to every property.

Well, I had one of the these objects directly bound in the UI.  Not thinking about it, I modified it in the PropertyGrid.

Surprise!

To my surprise I saw the databound value update in WPF after changing it in the PropertyGrid.  I was completely stumped, I’ve never seen this happen.  There were no events in the object being modified, so no way for WPF to have been alerted to the change occurring, and yet, there it was.

There must be some invisible connection between these two objects that I’ve never heard of.  Well, there is, the ValueChangedEventManager.  It’s a Microsoft internal class that is another weak event manager used by WPF.  Why Microsoft added it?  I’m not completely sure of the intended purpose, but as it turns out, every binding statement lets the ValueChangedEventManager know what it has databound and in return the binding statement is notified by ReflectPropertyDescriptor whenever they are changed through a call to SetValue.

The FauxValueChangedEventManager!

So what does this mean?  It means that with a little bit of reflection hackery, we too can harness this power for our own.  Wouldn’t it be nice to be able to directly attach business objects to the UI when it makes sense and still get updates? Enter the FauxValueChangedEventManager:


public static class FauxValueChangedEventManager
{
    private delegate void OnValueChanged(object sender, EventArgs args);
    private delegate object GetItem(object indexer);

    private static object m_currentManager;
    private static MethodInfo m_onValueChanaged;
    private static MethodInfo m_getItem;

    static FauxValueChangedEventManager()
    {
        Type managerType = Type.GetType("MS.Internal.Data.ValueChangedEventManager, PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
        PropertyInfo currentmanager = managerType.GetProperty("CurrentManager",
            BindingFlags.NonPublic | BindingFlags.Static);
        m_currentManager = currentmanager.GetValue(null, null);

        m_getItem = managerType.GetMethod("get_Item",
            BindingFlags.NonPublic | BindingFlags.Instance);

        Type valueChangedRecord = Type.GetType("MS.Internal.Data.ValueChangedEventManager+ValueChangedRecord, PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
        m_onValueChanaged = valueChangedRecord.GetMethod("OnValueChanged",
            BindingFlags.NonPublic | BindingFlags.Instance);
    }

    public static void NotifyPropertyChanged(object sender, string propertyName)
    {
        HybridDictionary records = (HybridDictionary)m_getItem.Invoke(
            m_currentManager, new object[] { sender });

        if (records != null)
        {
            var properties = TypeDescriptor.GetProperties(sender);
            var property = properties[propertyName];

            var record = records[property];
            if (record != null)
            {
                m_onValueChanaged.Invoke(record, new object[] { sender, null });
            }
        }
    }
}

Usage

After we modify a property on our business object, all we need to do to make sure WPF updates the binding (should one actually exist) is to do the following.


FauxValueChangedEventManager.NotifyPropertyChanged(businessObject,
    "PropertyName"); 

Further Extensions

While working on this I thought about combining it with the concept of a “DynamicObject-ViewModel”, which is just the idea that instead of specially designing a ViewModel, you could create one ViewModel that extends from DynamicObject. That way you can emit PropertyChanged events, without wrapping each property. There’s already a writeup on the concept elsewhere: Easy INotifyPropertyChanged Via DynamicObject Proxy.

However, you could extend the concept by also using the FauxValueChangedEventManager. To notify any other WPF UI that has databound itself directly to the underlying object (instead of the dynamic viewmodel). That way it too would update.

WPF ShaderEffect Generator 1.7

I’ve released an updated version of my WPF ShaderEffect Generator tool on Codeplex. The release is fairly minor but I figured I’d update my blog anyway.

Changes:

  • Added support for the DdxUvDdyUvRegisterIndex property.
  • DefaultValue tags work now.
  • It’s been compiled against the June DirectX SDK.

WPF: ViewModel + Attachable Behavior

One of the biggest pain points of MVVM is the boilerplate code that is necessary for it to function.  The code I’m referring to is the code needed to Hook and Unhook, initialize/shutdown, load/unload the things the ViewModel needs to do before and after being used by the View.  Because the ViewModel is usually forced to hook events coming from the Model to know when to emit its own set of events to update the View, it means knowing the lifetime of the View is critical to knowing when to unhook those events from the Model.

An idea I came up with while working on our level editor a few months back was this thought that, what if I could use the attached behavior pattern to actually solve the problems of ViewModels’s boilerplate code for hooking and unhooking those event on the model handlers.

First you’ll need a base class for your ViewModel, I actually went with an interface instead because I felt it was better suited for this role.  The ViewModel I decided to go with is extremely basic, there’s just a Load and Unload method and we also use the interface INotifyPropertyChanged.  In our own code I also defined a ViewModel class that derives from this interface that I tended to use most of the time, that just stubs out these methods with your basic implementations just so I didn’t need to implement a RaisePropertyChanged method 40 times.

C#
public interface IViewModel : INotifyPropertyChanged
{
    bool Initialized { get; set; }
    void Load(FrameworkElement element);
    void Unload(FrameworkElement element);
}

Next we need to create an attachable property that has logic associated with it that reacts to changes in the control, the community has come to call these attachable behaviors.

The job of this attachable behavior will be to notify our IViewModel that is databound to the control, when the control is loaded and when the control is unloaded.  That way we can just put all our event hooking and handling code into our ViewModel, and never need to worry about manually unhooking those events elsewhere ever again.

Whenever the DataContext on the View is changed, we want to Unload() the old ViewModel that was attached and Load() the new one.  Also, whenever the control is Loaded or Unloaded, do the same for the ViewModel.

There are some additional things that need to be taken into account when dealing with IsAsync=True DataContext’s.  Additionally there’s a bit of code to handle the problem with some WPF controls that actually sometimes send multiple Loaded events.

C#
public static class ViewModelBehavior
{
    public static readonly DependencyProperty LoadUnloadProperty =
        DependencyProperty.RegisterAttached("LoadUnload", typeof(Boolean),
        typeof(ViewModelBehavior),
        new FrameworkPropertyMetadata(false,
            new PropertyChangedCallback(OnLoadUnloadChanged)));
 
    public static void SetLoadUnload(FrameworkElement element, Boolean value)
    {
        element.SetValue(LoadUnloadProperty, value);
    }
 
    public static Boolean GetLoadUnload(FrameworkElement element)
    {
        return (Boolean)element.GetValue(LoadUnloadProperty);
    }
 
    public static void OnLoadUnloadChanged(DependencyObject obj,
        DependencyPropertyChangedEventArgs args)
    {
        FrameworkElement element = obj as FrameworkElement;
 
        if (element == null)
            throw new InvalidOperationException();
 
        element.DataContextChanged += (sender, e) =>
        {
            if (!element.IsLoaded)
                return;
 
            if (e.OldValue is IViewModel)
            {
                IViewModel viewModel = ((IViewModel)e.OldValue);
                if (viewModel.Initialized)
                {
                    viewModel.Unload(element);
                    viewModel.Initialized = false;
                }
            }
 
            if (e.NewValue is IViewModel)
            {
                IViewModel viewModel = ((IViewModel)e.NewValue);
                if (!viewModel.Initialized)
                {
                    viewModel.Initialized = true;
                    viewModel.Load(element);
                }
            }
        };
 
        element.Loaded += (sender, e) =>
        {
            IViewModel viewModel =
                element.GetValue(FrameworkElement.DataContextProperty) as IViewModel;
 
            if (viewModel != null && !viewModel.Initialized)
            {
                viewModel.Initialized = true;
                viewModel.Load(element);
            }
        };
 
        element.Unloaded += (sender, e) =>
        {
            IViewModel viewModel =
                element.GetValue(FrameworkElement.DataContextProperty) as IViewModel;
 
            if (viewModel != null && viewModel.Initialized)
            {
                viewModel.Unload(element);
                viewModel.Initialized = false;
            }
        };
    }
}

The way you would use this is to place the property on the controls that are the primary targets when you’re data binding your ViewModel to your view on.  For example, suppose I had a ListBox with a series of ListBoxItems, there was a ViewModel databound as the ItemsSource of the ListBox (which will also set the DataContext of the ListBox to the ItemsSource).  Also imagine that there is a ViewModel for each item in the list.  You would place the following property on the ListBox declaration in XAML.  You would also place this property on the first control element of whatever DataTemplate you defined for the ViewModel representing each element in the list.

XAML
ViewModelBehavior.LoadUnload="True"

You can download the full source files for both of these classes here, there is more documentation for these classes in those files that I didn’t want to include in the post.

[IViewModel.cs and ViewModelBehavior.cs]

The CLR Team Needs Feedback

So [over at the CLR Team Blog] they’re asking users to send them feedback on what kinds of things they should be focusing on for the next version. Even though it’s the CLR team, the survey touches on pretty much everything in the software life cycle and not just the CLR specifically.

If you’re like me and you use .Net a lot. Take some time to tell them about where the pain points are and the stuff you like. I hope more teams over at Microsoft have these kinds of surveys each release.

WPF: Heat Maps

So awhile ago I thought, “Wouldn’t it be cool to do heat maps in WPF?”.  Well I started playing around with the idea and immediately was side tracked with how terrible shaders were in WPF :)  Which of course lead to me creating the [WPF ShaderEffect Generator] project.

Now that I have that project off and running I turned my attention back to heat maps and thought I would publish the results.  So I started off with the typical visualization I see everywhere; the rainbow color scheme.  Once I got it running I was showing it off to some of my friends and my good buddy [Chris VanderKnyff] told me about this paper, [Rainbow Color Map (Still) Considered Harmful].  I hadn’t really thought much about it before reading the paper, but the rainbow color scheme really is terrible.  The paper suggests that a Black body radiation visualization is generally better for the types of things you might use a heat map for in tools for games.

Here’s a comparison of the Rainbow and Black body gradients:

Black body Radiation
Gradient

lava
Blackbody Palatte Blackbody HeatMap

Rainbow Cream
Gradient

rainbowcream
Classic Palatte Classic HeatMap

Obviously the black body visualization of heat is much more simple and easy to understand than the rainbow visualization.

The WPF sample uses a shader to visualize the gradient based on a 256×1 palette that you can define in XAML.  Random heat is generated and then rendered to a [RenderTargetBitmap] using a radial grayscale gradient brush that just writes to the rendertargetbitmap.  The color for the heat map is provided by a shader effect I have applied to the image on the window.

The shader is pretty simple, it just reads a color from the palette sampler based on the grayscale value of the X (Red) component of the incoming rendertargetbitmap at the corresponding texture coordinate.

HLSL
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float4 c = tex2D(Input, uv.xy);
    float2 index = float2(c.x, 0);
    float4 heat = tex2D(Palette, index);
    return heat;
}

Here’s a screenshot of the sample program and the links to download the sample exe and source code.

HeatmapProgram

Sample: [Heatmap.exe]

Sample Source: [Heatmap.zip]

Note: You should have the [WPF ShaderEffect Generator] installed if you want the shaders to recompile correctly if they are changed.