From Dr.WPF 的Tabcontrol的MVVM性能问题
2010-10-25 21:24
543 查看
(http://groups.google.com/group/wpf-disciples/browse_thread/thread/6f3531a1720252dd?pli=1)
(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[1] 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);
}
}
(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[1] 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);
}
}
相关文章推荐
- WPF TabControl控件-事件相关问题
- WPF 中关于TabControl选项卡中UserControl的问题
- WPF下 使用它tabcontrol控件 时遇到的指定控件获得焦点的问题
- 关于WPF画图性能问题
- 【WPF收藏】隐藏TabControl标签(按钮)的方法(Hide the TabStrip of a TabControl)
- C# TabConTrol控件背景颜色问题
- wpf利用后台生成grid表格以及tabcontrol,border等用法
- WPF 的 TabControl 绑定不同的窗口集合
- PNG图片导致的WPF性能问题
- WPF&MVVM线程问题(progressbar为例)
- 【WPF】【DevExpress】定制TreeListControl中显示列的样式+MVVM架构
- wpf TabControl TabItem 被点击信息
- C#中关于TabControl设置选项卡的大小问题
- WPF+MVVM数据绑定问题集锦
- 修复TabControl在Binding情况下Canvas被复用的问题
- 为WPF中TabControl的TabItem添加图片
- Silverlight中的TabControl如何绑定数据?重写tabcontrol和tabItem 解决绑定友好问题。可以绑定对象集合
- wpf中使用mvvm,解决checkbox全选问题
- WPF Customize TabControl
- 让 wpf tabcontrol 延缓初始化每个tab item content