Outlook style regions

Jul 16, 2008 at 2:53 PM
I am building a composite application with outlook layout. The left hand navigation (nav region) is a tree structure with modules as parent nodes and their respective views as child nodes. The right hand region (content region) should load a view when I select something from left hand tree. It should show only the selected view, hiding all other views. What's the best way of doing this. I saw code samples on adding views to regions but nothing about replacing views. Please provide code sample to explain the solution.

Thanks
Jul 16, 2008 at 3:08 PM
You can achieve this effect by skinning a tabcontrol that you use as a region for your outlookbar panes. A sample on how to skin the tabcontrol in such a way that it looks like an outlookbar is shown here on codeproject: http://www.codeproject.com/KB/WPF/XAML_OutlookBar.aspx

For the rest I can recommend on a construction where you bind the Title property of your view to the header property of a tabitem. A sample of this is shown here: http://blogs.infosupport.com/blogs/willemm/archive/2008/07/15/Customizing-regions-in-CompositeWPF.aspx
Jul 17, 2008 at 2:46 PM

I, perhaps, did not phrase my question correctly. The specific problem, I am trying to solve, is to load/unload views in a given region on demand. My solution can have, potentially, hundreds of views and I want to display only one or two views at a time depending on user's selection.

One approach, I was thinking to take had to deactivate/remove views from region's activeviews collection before adding a new view. This may have performance implications though. Is there a better way of displaying only one of the activeviews at a time? while keeping all others hidden.


WMeints wrote:
You can achieve this effect by skinning a tabcontrol that you use as a region for your outlookbar panes. A sample on how to skin the tabcontrol in such a way that it looks like an outlookbar is shown here on codeproject: http://www.codeproject.com/KB/WPF/XAML_OutlookBar.aspx

For the rest I can recommend on a construction where you bind the Title property of your view to the header property of a tabitem. A sample of this is shown here: http://blogs.infosupport.com/blogs/willemm/archive/2008/07/15/Customizing-regions-in-CompositeWPF.aspx


Jul 17, 2008 at 4:02 PM
You can iterate over all views in a specific region and remove them. After that you can insert the views you require.
It will however take a little more work to get this working cross module.

I can think up a scenario like the following:

1. Remove all views from the required regions
2. Fire a global event to indicate that a specific scenario is started
3. All modules that are part of a scenario add the views they require for the specified scenario

I don't think you want this cross module, but it can be done :)
Jul 17, 2008 at 4:25 PM
Edited Jul 17, 2008 at 6:27 PM
Ok, this may sound like a dumb coding issue from my end but I really can not do something like

 

foreach (object v in _regionManager.Regions[RegionNames.Contents].Views)  {

 _regionManager.Regions[RegionNames.Contents].Remove(v);

  }

The reason being, I get following exception

"Collection was modified; enumeration operation may not execute."

I was hoping a more straight forward way of emptying out a collection, instead of iterating through it.

 

 

Secondly, yes I do have a cross-module situation but I'll deal with it later.  

 

 

 

 

 

 

Jul 17, 2008 at 6:44 PM
This is not pretty but I made it to work following way. Don't like it but can live with it for now.

System.Collections.ArrayList activeViews = new System.Collections.ArrayList();
                       
foreach (object v in _regionManager.Regions[RegionNames.Contents].Views)
{
    activeViews.Add(v);
}

foreach (object v in activeViews)
{
    _regionManager.Regions[RegionNames.Contents].Remove(v);
}


Jul 18, 2008 at 1:53 AM
Hi zi, the reason you get the exception is because IEnumerator must detect alterations to the underlying collection and throw a System.InvalidOperationException if a call is made to any of the interface members if it has been altered since the enumerator was created.

The good news is that System.Collections.Generic.List has an overloaded constructor that takes an enumerator. Knowing this, you can do the following:

    foreach (object v in new List<object>(_regionManager.Regions[RegionNames.Contents].Views)) {
        _regionManager.Regions[RegionNames.Contents].Remove(v);
    }

Although, this is just the solution to your latest problem, not your initial one, I hope it helps :)
-Brett.

Jul 22, 2008 at 12:32 AM
Hi guys, I've just blogged about how to use the OutlookBar in CompositeWPF applications.
Hope you find the post useful. 

Feeback is welcome.

Ezequiel Jadib
http://blogs.southworks.net/ejadib
Oct 9, 2008 at 5:07 PM
Edited Oct 10, 2008 at 1:39 PM
I came up with the following.
On all Views I have a interface defined (IView). This interface makes sure that all views have a property called "Visibility".

IView.cs
    public interface IView
    {
        Visibility Visibility { get; set; }
    }


XxxxView.cs
        public new Visibility Visibility
        {
            get { return base.Visibility; }
            set { base.Visibility = value; }
        }

Anyway, I now have the possiblity to hidde, collapse or make the view visible.

            foreach (object item in new List<object>(this.regionManager.Regions["ListRegion"].Views))
            {
                ((IView)item).Visibility = Visibility.Collapsed;
            }
            view.Visibility = Visibility.Visible;

Update 10.Oct.2008:

You can also just use the FrameworkElement, without implementing a Interface:

            foreach (object item in new List<object>(this.regionManager.Regions["DetailRegion"].Views))
            {
                (item as FrameworkElement).Visibility = Visibility.Collapsed;
            }

            (view as FrameworkElement).Visibility = Visibility.Visible;