Using IActiveAware

Topics: Prism v2 - WPF 3.5
Apr 30, 2009 at 2:08 PM
Hi,
Let's say  I have two views LeftView and RightView.  I have a toolbar and a menu bar implemented as separate UserControls.  When my LeftView becomes active, I need to disable certain buttons and menuItems from the toolbar and menubar respectively.  My buttons on the toolbar and menuitems are bound to commands.  

My question is how do I leverage IActiveAware to disable/enable toolbat buttons and menuItems?  Are there any samples around that do this.

Thanks,
Arun
May 4, 2009 at 8:51 PM

Hi Arun,

 

The IActiveAware interface  defines if the object instance is active and notifies when the activity changes. You should implement for your objects that need to know if they are active or need to communicate their activity changes. For example in Prism-v2 this interface is used by the CompositeCommand class not to execute Commands that are inactive. RegionActiveAwareBehavior notifies views that implement IActiveAware when they are activated /deactivated.

 

To leverage the IActiveAware interface in your scenario, you can implement it in your LeftView and RightView  so that they are notified when they are activated /deactivated and they can notify about this change.

To implement the enabling or disabling the buttons in the toolbar,  it depends on your particular scenario. If the commands bound to the buttons are used by several modules you will be using Globally Available Commnads. One possible solution might be having a CompositeCommand that should be accessible to the view and to the toolbar. This way the view could register a DelegateCommand in the CompositeCommnad that will have an empty ExecuteMethod  and the CanExecute method using the IsActive property of the view. For example you can do the following in the view's constructor:

 

      public LeftView()

{

    InitializeComponent();

 

    // Declare the command

    this.activeCommand = new DelegateCommand<object>(param => { return; }, param => this.IsActive);

 

    // add command to the composite command

    Commands.ToolBarCommand.RegisterCommand(this.activeCommand);

}

               

      public bool IsActive

      {

            get

            {

                return this._isActive;

            }

            set

            {

                if (this._isActive != value)

                {

                    this._isActive = value;                   

                    OnIsActiveChanged();

                    this.activeCommand.RaiseCanExecuteChanged();

                }

            }

       }         

 

This way the ToolBarCommand will be able to execute only if the LeftView is active and this will automatically enable /disable the controls bound to this command.

 

One more thing to notice is that you should be careful about which control you are using as region, because this will change the way it's views are considered active. For example, a ContentControl will always have one active view (the one that is showing), the ItemsControl and TabContol might have several active views (even if they are not being shown in the UI).

 

Hope it helps!

 

Matias Bonaventura

http://blogs.southworks.net/matiasb

Aug 14, 2009 at 8:33 AM

Just wanted to post an implementation that you might find useful in a scenario like the one described. Feel free to let me know flaws in the thinking or better ways to achieve the same thing.

 

I am using a TabControl region with a close button which I wanted to hide in the unselected tabs. The steps I took in my MVVM/MVP style project:

 

  1. Bind a local command in the presenter to the close button in the shell's TabItem HeaderTemplate .
  2. Implement IActiveAware on the views that will be shown in the tabs. These views are given a reference to their presenter. This presenter holds a property for CloseCanExecute and it is set to true or false when the view is activated and inactivated (in the IActiveAware IsActive setter - I feel that this is an acceptable use of a property side effect? Chime in!).
  3. In my shell XAML where the TabControl resides, I added a reference to a value converter which converts a boolean to a Visibility value. I bound the Visibility of a container holding the button to the close button's IsEnabled property through the converter. I would guess you could bind the button's own Visibility property as well. Element binding in SL3 = Fresh. (You should still be able to make this work in SL2 with a propety in your presenter and INotifyPropertyChanged)

 

That's it. When you flip the bit on the CloseCanExecute property (when a View is activated or deactivated), the button's IsEnabled property is toggled, converted to a Visibility of collapsed or visible and applied to the button. Visually, it's a little blinky (you see the button momentarily before it disappears) - will have to figure out what can be done about that later - but it works in a reasonably nice "Prism kind of way".

 

P.S. Any suggestions on dealing with the blink would be greatly appreciated. ;)

 

Rock.

 

Best wishes...

Aug 14, 2009 at 6:39 PM

Update: Changed the button to bind to itself and eliminated the container - visual performance is much better. Looks like this:

 

 

<Button x:Name="btnClose" Visibility="{Binding IsEnabled, Mode=OneWay, ElementName=btnClose, Converter={StaticResource VisibilityConverter}}" />

 

 

Oct 15, 2009 at 9:02 PM

Can you post the VisibilityConverter?  Thanks.

Oct 19, 2009 at 11:53 PM

Apologies for the late reply. I used the approach detailed here:

 

http://www.jeff.wilcox.name/2008/07/visibility-type-converter/

 

Best of luck!