Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where to access DataContext in WinRT XAML UserControl

I've got UserControlViewModel which raises an event:

public event EventHandler<EventArgs> StuffDone;

An object of UserControlViewModel is created and initialised inside MainPageViewModel:

this.userControlViewModel = new UserControlViewModel();

MainPageViewModel is the View-Model for MainPage.

In MainPage.xaml, I've got the following code to place UserControlView UserControl in MainPage and initialise its DataContext:

<views:UserControlView DataContext="{Binding userControlViewModel, Mode=OneWay}" IsHitTestVisible="False"></views:UserControlView>

So far everything works fine.

Now I'd like to subscribe to StuffDone event inside UserControlView. The first thing occurred to me is to do it inside Loaded event-handler of UserControlView; however, the DataContext at that point is still null. Scanning the rest of UserControl events gave me no clue at all.

So, where is the right place to get the DataContext and subscribe to its events?

Thanks in advance.

like image 610
TheBlueSky Avatar asked Nov 13 '22 10:11

TheBlueSky


1 Answers

UPDATE: DataContextChanged event is supported in WinRT for Windows 8.1. Use the following only if you're coding against WinRT for Windows 8, or whatever platform that does not support DataContextChanged.

Seems like there is no straightforward way to do it and the workaround suggested by Will on his comment is the simplest way to go.

Below is my version of the workaround which works for me:

In IDataContextChangedHandler.Generic.cs:

using Windows.UI.Xaml;

namespace SomeNamespace
{
    public interface IDataContextChangedHandler<in T> where T : FrameworkElement
    {
        void DataContextChanged(T sender, DependencyPropertyChangedEventArgs e);
    }
}

In DataContextChangedHelper.Generic.cs:

using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;

namespace SomeNamespace
{
    public sealed class DataContextChangedHandler<T> where T : FrameworkElement, IDataContextChangedHandler<T>
    {
        private readonly DependencyProperty internalDataContextProperty =
            DependencyProperty.Register(
                "InternalDataContext",
                typeof(object),
                typeof(T),
                new PropertyMetadata(null, DataContextChanged));

        private static void DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var control = sender as T;

            if (control == null) { return; }

            control.DataContextChanged(control, e);
        }

        public void Bind(T control)
        {
            control.SetBinding(this.internalDataContextProperty, new Binding());
        }
    }
}

In UserControlView.xaml.cs:

using Windows.UI.Xaml;

namespace SomeNamespace
{
    public sealed partial class UserControlView : IDataContextChangedHandler<UserControlView>
    {
        private readonly DataContextChangedHandler<UserControlView> handler = new DataContextChangedHandler<UserControlView>();

        public UserControlView()
        {
            this.InitializeComponent();

            this.handler.Bind(this);
        }

        public void DataContextChanged(UserControlView sender, DependencyPropertyChangedEventArgs e)
        {
            var viewModel = e.NewValue as UserControlViewModel;

            if (viewModel == null) { return; }

            viewModel.SomeEventRaised += (o, args) => VisualStateManager.GoToState(this, "TheOtherState", false);
        }
    }
}

Hope that helps.

like image 91
TheBlueSky Avatar answered Jan 04 '23 03:01

TheBlueSky