RE: Question for the group

5,475 views
Skip to first unread message

Dr. WPF

unread,
Mar 12, 2009, 1:59:13 PM3/12/09
to wpf-di...@googlegroups.com

(moving to public group)

This topic is on my todo list for my ItemsControl series.  I just need to find some blog time.

I have repeatedly brought this issue up with Microsoft (including last week at the summit).  I understand why they chose to implement it this way, but its not practical for most TabControl scenarios. I want them to add an option to cache the tab items.

The perf hit is during the building of the tree.  Unfortunately, if you're using a typical MVVM approach with a binding on the ItemsSource property of the TabControl, the entire tree must be rebuilt each time a tab item is selected.  This is usually a very expensive operation.

To be clear, I don't mind that they unload/reload the items each time.  I just don't want the entire tree discarded.  By doing this, all state associated with the visuals is lost.  Maintaining that state in the VM is usually an unreasonable nightmare.

The discarding of items is really only a problem when using a TabControl in ItemsSource mode.  In Direct mode, the visuals will still be unloaded from the tree, but they won't be discarded.  (See 'C' is for Collection for a description of Direct vs ItemsSource.)

This means you can solve the problem by creating your own TabItem objects and manually adding them to the TabControl's Items collection.  Yes, this adds a bunch of overhead to the view (which is why I wish Microsoft would solve the problem in the platform), but if done right, it still allows an MVVM approach.  You just don't get to use an ItemsSource binding on the TabControl. 

Below is what my view code typically looks like for such an approach:

private void OnLoaded(object sender, RoutedEventArgs e)
{
    // set initial tabs
    foreach (TabViewModel view in TabsCollection)
    {
        AddTabItem(view);
    }

    // monitor tabs collection for changes so that tabs can be updated appropriately
    TabsCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(OnViewsCollectionChanged);
}

private void OnViewsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    switch (e.Action)
    {
        case NotifyCollectionChangedAction.Add:
            foreach (TabViewModel view in e.NewItems)
            {
                AddTabItem(view);
            }
            break;

        case NotifyCollectionChangedAction.Remove:
            foreach (TabViewModel view in e.OldItems)
            {
                RemoveTabItem(view);
            }
            break;

        case NotifyCollectionChangedAction.Reset:
            _tabControl.Items.Clear();
            foreach (TabViewModel view in e.NewItems)
            {
                AddTabItem(view);
            }
            break;
    }
}

private void AddTabItem(TabViewModel view)
{
    TabItem item = new TabItem();
    item.DataContext = view;
    item.Content = new ContentControl();
    (item.Content as ContentControl).Focusable = false;
    (item.Content as ContentControl).SetBinding(ContentControl.ContentProperty, new Binding());
    _tabControl.Items.Add(item);
}

private void RemoveTabItem(TabViewModel view)
{
    TabItem foundItem = null;
    foreach (TabItem tabItem in _tabControl.Items)
    {
        if (tabItem.DataContext == view)
        {
            foundItem = tabItem;
            break;
        }
    }
    if (foundItem != null)
    {
        _tabControl.Items.Remove(foundItem);
    }
}

Quoting "wpf-discip...@googlegroups.com" <wpf-discip...@googlegroups.com>:

>
> Yeah I am thinking that may have to be the way of things.
>
>
>
> Subject: RE: Question for the group
> Date: Thu, 12 Mar 2009 08:54:33 -0700
> From: ka...@littlerichie.com
> To: wpf-discip...@googlegroups.com
>
>
>
>
>
>
>
> Sacha,
>
> You can always roll your own, using an ItemsControl.  I've actually 
> thought about doing this.
>
> As for the TabControl, Josh is right on.  It Unloads and Loads based 
> on the selected tab.
>
> Cheers,
>
> k-dawg  (still feeling the MVP flu)
>
>
>
> From: wpf-discip...@googlegroups.com on behalf of Josh Smith
> Sent: Thu 3/12/2009 8:39 AM
> To: wpf-discip...@googlegroups.com
> Subject: Re: Question for the group
>
>
> It virtualizes, but not in the typical sense of UI virtualization.   
> The elements living in a TabItem are unloaded when that item is 
> deselected.  When the item is selected again, the UI elements in it 
> are loaded back up.  Basically, the visual tree of TabControl only 
> includes the elements within the selected TabItem.  As far as I 
> know, you cannot tell it not to do that.  What is the exact problem 
> you're trying to solve?
>
> Josh
>
>
> On Thu, Mar 12, 2009 at 11:33 AM, Sacha Barber 
> <sacha...@hotmail.com> wrote:
>
>
> Hello wise group members
>
>
> I have a small question for the group about TabControl in WPF.
>
> We are experiencing a small lag with an app I am working on, where 
> we are using Tabs where our content panes are new TabItems. All cool.
>
> The question I have is this
>
> Does the WPF TabControl Virtualize its children (I think it does), 
> where by only the current tab is shown and all other tabs are not 
> created until they need to be shown again, via the selected tab 
> changing.
>
> Is this the case. And if this is the case is there a way to stop the 
> TabControl virtualizing. Can I simply use the 
> VirtualizingStackPanel.IsVirtualizing or one of the new Recycle modes.
>
> What is the best option?
>
> I guess if I instuct the TabControl to not Virtualize, more memory 
> will be used, but the ayout may be quicker, as it is not having to 
> recreate the content each time for the newly selected TabItem.
>
> Any ideas/thoughts?
>
>
>
> Windows Live Hotmail just got better. Find out more!
>
>
>
>
>
> _________________________________________________________________
> All your Twitter and other social updates in one place
> http://clk.atdmt.com/UKM/go/137984870/direct/01/
> />>
>

Dr. WPF - Online Office at http://www.drwpf.com/blog/


Josh Smith

unread,
Mar 12, 2009, 2:04:52 PM3/12/09
to wpf-di...@googlegroups.com
Cool approach, Doc.  I think this code might create a good reason for a TabControl subclass.  Do you agree?

a...@drwpf.com

unread,
Mar 12, 2009, 2:12:48 PM3/12/09
to WPF Disciples
Absolutely. In fact, I have a sample that does this very thing. It
basically allows a binding on an alternate property (TabItemsSource)
and uses the TabControl in direct mode under the covers.

Like I said... I just need time to blog it! Grrr.... Maybe at Mix.

On Mar 12, 11:04 am, Josh Smith <flappleja...@gmail.com> wrote:
> Cool approach, Doc.  I think this code might create a good reason for a
> TabControl subclass.  Do you agree?
>
>
>
> On Thu, Mar 12, 2009 at 1:59 PM, Dr. WPF <a...@drwpf.com> wrote:
> > (moving to public group)
>
> > This topic is on my todo list for my ItemsControl series.  I just need to
> > find some blog time.
>
> > I have repeatedly brought this issue up with Microsoft (including last week
> > at the summit).  I understand why they chose to implement it this way, but
> > its not practical for most TabControl scenarios. I want them to add an
> > option to cache the tab items.
>
> > The perf hit is during the building of the tree.  Unfortunately, if you're
> > using a typical MVVM approach with a binding on the ItemsSource property of
> > the TabControl, the entire tree must be rebuilt each time a tab item is
> > selected.  This is usually a very expensive operation.
>
> > To be clear, I don't mind that they unload/reload the items each time.  I
> > just don't want the entire tree discarded.  By doing this, all state
> > associated with the visuals is lost.  Maintaining that state in the VM is
> > usually an unreasonable nightmare.
>
> > The discarding of items is really only a problem when using a TabControl in
> > ItemsSource mode.  In Direct mode, the visuals will still be unloaded from
> > the tree, but they won't be discarded.  (See 'C' is for Collection<http://drwpf.com/blog/Home/tabid/36/EntryID/18/Default.aspx> for
> > > From: k...@littlerichie.com
> > Dr. WPF - Online Office athttp://www.drwpf.com/blog/- Hide quoted text -
>
> - Show quoted text -

Josh Smith

unread,
Mar 12, 2009, 2:14:14 PM3/12/09
to wpf-di...@googlegroups.com
The world awaits that blog post with bated breath. :)

Sacha Barber

unread,
Mar 12, 2009, 3:18:34 PM3/12/09
to wpf-di...@googlegroups.com
Mike

Yeah we have some custom logic around loaded so it only happens once

Dr WPF

We do actually add the Tabs in code. And using MVVM for this just didnt fit.

I think what we will do is create a totaly specific solution, for our puposes which may start with ItemsControl or Selector.

GRRRR why is it so hard



Date: Thu, 12 Mar 2009 12:59:13 -0500
From: a...@drwpf.com
To: wpf-di...@googlegroups.com
Subject: [WPF Disciples] RE: Question for the group

Windows Live Messenger just got better. Find out more!

Corrado Cavalli

unread,
Mar 13, 2009, 2:29:23 AM3/13/09
to wpf-di...@googlegroups.com

I’m here waiting on queue… J (BTW: Great explanation doc!)

 

From: wpf-di...@googlegroups.com [mailto:wpf-di...@googlegroups.com] On Behalf Of Josh Smith


Sent: giovedì 12 marzo 2009 19:14
To: wpf-di...@googlegroups.com

Subject: [WPF Disciples] Re: Question for the group

 

The world awaits that blog post with bated breath. :)

On Thu, Mar 12, 2009 at 2:12 PM, <a...@drwpf.com> wrote:

Reply all
Reply to author
Forward
0 new messages