Setting IsActive on IActiveAware after view is added to object tree

Topics: Prism v4 - Silverlight 4
Dec 30, 2010 at 8:18 AM

I´ve noticed that IsActive is set on IActiveAware interface before a view is loaded and added to the object tree. Is this behavior by design?

Wouldn´t it be better to set IsActive after a view (userControl) is loaded?

 

public partial class ActiveAwareView : UserControl, IActiveAware {
        private bool _isActive;
        public event EventHandler IsActiveChanged;

        public ActiveAwareView () {
          InitializeComponent();
          this.Loaded += new RoutedEventHandler(View_Loaded);
        }

        void View_Loaded(object sender, RoutedEventArgs e) {
            System.Diagnostics.Debug.WriteLine("Loaded");
        }

        public bool IsActive {
            get {
                return _isActive;
            }
            set {
                if (value == _isActive) {
                    return;
                }

                _isActive = value;
                OnActiveChanged(EventArgs.Empty);               

                System.Diagnostics.Debug.WriteLine("IsActive changed");
            }
        }

        private void OnActiveChanged(EventArgs e) {
            var handler = IsActiveChanged;

            if (handler != null) {
                handler(this, e);
            }
        }
}

Developer
Dec 30, 2010 at 5:46 PM
Edited Dec 30, 2010 at 5:49 PM

Hi,

The behavior you're mentioning is by design. There is a Region Behavior responsible for setting the IsActive property of a view to true when adding it to a region (the RegionActiveAwareBehavior behavior, which can be found in the Regions/Behaviors folder in the Prism.Silverlight project). The aforementioned behavior monitors the region's ActiveViews collection to see if a view is added or removed (by subscribing to its CollectionChanged event). The ActiveViews collection (which is an instance of the ViewsCollection class) is a collection of ItemMetadata, which are wrappers that contain a view (of object type) and metadata for it, such as a Name and a property indicating whether it is active. So the ActiveViews collection of a region contains all the views that should be considered active for that region. When a view that implements IActiveAware is added to that ActiveViews collection, the RegionActiveAwareBehavior sets the IsActive property of the View and its DataContext (if any) to true, and to false in case it is removed from that collection. Since the views that can be added to regions aren't constrained to FrameworkElements, you could add any kind of object to a region, which does not necessarily implement the FrameworkElement.Loaded event.

You could, however, consider extending Prism to implement a different RegionActiveAwareBehavior that sets the IsActive property of a view to true only when it is loaded. In that case, you should note that only views that inherit from FrameworkElement could be affected by that behavior. Another possibility would be to add a different implementation of the IActiveAware interface in your active aware view. For example, you could modify the getter of your IsActive property to return (_isActive && this._contentLoaded) instead of just _isActive, so that your view is only considered active when it has already been loaded. An example to illustrate this could look like the following:

 

public partial class ActiveAwareView : UserControl, IActiveAware
    {
        private bool _isActive;
        public event EventHandler IsActiveChanged;
        private bool _alreadyLoaded;

        public ActiveAwareView()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(View_Loaded);
        }

        void View_Loaded(object sender, RoutedEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Loaded (now the view is considered active)");
            this._alreadyLoaded = true;
        }

        public bool IsActive
        {
            get
            {
                return (_isActive && this._alreadyLoaded);
            }
            set
            {
                if (value == _isActive)
                {
                    return;
                }

                _isActive = value;
                OnActiveChanged(EventArgs.Empty);

                System.Diagnostics.Debug.WriteLine("IsActive changed (but the view is still considered not active");
            }
        }

        private void OnActiveChanged(EventArgs e)
        {
            var handler = IsActiveChanged;

            if (handler != null)
            {
                handler(this, e);
            }
        }
    }

If you consider this to be an undesired behavior for Prism, you could create a work item in the Issue Tracker for this to be modified in future releases.

I hope you find this helpful.

Guido Leandro Maliandi
http://blogs.southworks.net/gmaliandi