jbe2277 / waf

Win Application Framework (WAF) is a lightweight Framework that helps you to create well structured XAML Applications.
MIT License
710 stars 128 forks source link

DataContext is set too early when using MEF #19

Open maikhanns opened 2 years ago

maikhanns commented 2 years ago

We have migrated an WPF application from an old WPFApplicationFramework version to System.WAF.

Our application uses MEF and a plugin class that inherits from ViewModel. The plugins have an additional Initialize method. So far the DataContext was set after this method. (Dispatcher.BeginInvoke in ViewModel)

Since System.WAF 4.0.0-alpha3 that behavior changed. The DataContext is already set after the MEF import and before our Initialize method.

This leads to the fact that bindings are already executed on a plugin that is not initialized for us. Within the application there are e.g. also DataContextChanged events which are now executed too early.

Is it possible to prevent the setting of the DataContext in the OnImportsSatisfied or to get more control over it?

Thanks in advance :-)

jbe2277 commented 2 years ago

Explanation: I have changed the behavior of initializing the DataContext within the ViewModel because the delay created by Dispatcher.BeginInvoke produced some issues when using nested ViewModels. However, this is a MEF based solution and so it works only when using MEF. If other ways are used to create the ViewModels then still the Dispatcher.BeginInvoke solution is used.

Solutions: Here are possible solutions for your requirements:

  1. Approach: Implement your own ViewModel base class to get the old WAF behavior:
    public abstract class ViewModel2<TView> : ViewModelCore<TView> where TView : IView
    {
    protected ViewModel2(TView view) : base(view, false)
    {
        if (SynchronizationContext.Current is DispatcherSynchronizationContext)
        {
            Dispatcher.CurrentDispatcher.BeginInvoke((Action)delegate
            {
                ViewCore.DataContext = this;
            });
        }
        else
        {
            view.DataContext = this;
        }
    }
    }
  2. Approach: Don't use the automatic DataContext initialization at all. Do it yourself in your Initialize method. Use ViewModelCore base class for that and call Initialize on the base class to set the DataContext.

I use the second approach for Xamarin and other non-WPF applications.