Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Create Generic ReactiveUserControl<ViewModel> #348

bradphelan opened this Issue Jul 17, 2013 · 3 comments


None yet
3 participants

Even though generic view classes are a bit of a pain in WPF they can be done and this class adds some very nice behaviors.

using ReactiveUI.Ext;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Reactive.Linq;
using System.Windows.Media;
using System.Reactive.Disposables;
using System.Windows.Markup;
using System.Windows.Controls.Primitives;

namespace ReactiveUI
    public class ReactiveUserControl<ViewModelT> : UserControl, IViewFor<ViewModelT>
        where ViewModelT : class 
        #region IViewFor<ViewModelT>
        public static readonly DependencyProperty ViewModelProperty =
            DependencyProperty.Register("ViewModel", typeof(ViewModelT), typeof(ReactiveUserControl<ViewModelT>), new PropertyMetadata(null));

        public ViewModelT ViewModel
            get { return (ViewModelT)GetValue(ViewModelProperty); }
            set { SetValue(ViewModelProperty, value); }

        object IViewFor.ViewModel
            get { return (ViewModelT)GetValue(ViewModelProperty); }
            set { SetValue(ViewModelProperty, value); }

        /// <summary>
        /// Gets or sets additional content for the UserControl. The additional
        /// content will have it's DataContext set to an instance of the ViewModel
        /// </summary>
        public UIElement AdditionalContent
            get { return (UIElement)GetValue(AdditionalContentProperty); }
            set { SetValue(AdditionalContentProperty, value); }

        public static readonly DependencyProperty AdditionalContentProperty =
            DependencyProperty.Register("AdditionalContent", typeof(UIElement), typeof(ReactiveUserControl<ViewModelT>),
              new PropertyMetadata(null));

        public IObservable<ViewModelT> ViewModelObservable()
            return this.WhenAny(x => x.ViewModel, x => x.Value)

        public UniformGrid DataContextHost { get; private set; }

        public ReactiveUserControl()
            DataContextHost = new UniformGrid();
            this.Content = DataContextHost;

            // If AdditionalContent changes then we need to
            // add it to the visual tree
            this.WhenAny(p => p.AdditionalContent, p => p.Value)
                .Subscribe(v => {

            // If the ViewModel changes we need to ensure the
            // AdditionalContent get's the correct DataContext
            this.WhenAny(x => x.ViewModel, x => x.Value)
                .BindTo(this, x=>x.DataContextHost.DataContext);

            if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))



        public virtual void DesignUnsafeConstruct(){

        public virtual void DesignSafeConstruct(){

    public static class ReactiveUserControlMixins
        // Dispose the previous disposable when the next is registered
        // and then dispose the last one when the UI is shut down
        public static void SeriallyDisposeWith(this IObservable<IDisposable> This, Control control)
            var disposer = new SerialDisposable();
            control.Unloaded += (s, e) => disposer.Dispose();
            control.Dispatcher.ShutdownStarted += (s, e) => disposer.Dispose();

        // Dispose when unloaded or dispatcher is shut down
        public static void DisposeWith(this IDisposable This,  Control contrl)
            contrl.Unloaded += (s, e) => This.Dispose();
            contrl.Dispatcher.ShutdownStarted += (s, e) => This.Dispose();


Usage is something like

namespace WeinCad.Controls.View
    public class MoineauMillingViewBase : ReactiveUserControl<MoineauMillingViewModel> { }
    /// <summary>
    /// Interaction logic for MoineauMillingView.xaml
    /// </summary>
    public partial class MoineauMillingView : MoineauMillingViewBase
        public MoineauMillingView()

and in XAML

<l:MoineauMillingViewBase x:Class="WeinCad.Controls.View.MoineauMillingView"
             d:DesignHeight="300" d:DesignWidth="300">
        <Label>Moin Moin Milling</Label>


The reactiveuser control wraps internal content in a hidden control on which the datacontext is set to the ViewModel. This automatically protects the internal DataContext from being set if a user directly sets the DataContext on an instance of the control.

There are also some helpers for managing IDisposable lifetimes in terms of load and unload events.

It's not a pull request as I have this code internal to my codebase but if you like I'll take the effort to make a patch


Haacked commented Jul 17, 2013

Geez! You're taking all my good ideas right out of my brain! I had thought of doing this too but have been too busy. I ❤️ it!

I wonder if we should add some of the common Bind methods too. That way you don't have to do the awkward this.Bind(...) calls.

@bradphelan bradphelan added a commit to bradphelan/ReactiveUI that referenced this issue Jul 18, 2013

@bradphelan bradphelan Fixes #348 358bffb

@Haacked I've created a pull request so you can try out the branch if you like. The feature I'd really like is a template where I can click New ReactiveUserControl and all the nasty XAML boilerplate and namespace crap is filled in for me. That would be a nice addition if anybody has experience with that stuff.


jlaanstra commented Apr 27, 2014

Tracked in #349.

@jlaanstra jlaanstra closed this Apr 27, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment