How to Achieve Lazy Binding of Tab Page Controls in WPF?

空扰寡人 提交于 2019-11-30 05:29:11

You don't have anything to do, that's the default behavior. The DataTemplate for a TabItem content won't be instantiated until this TabItem is selected


EDIT: here's an example:

<Window.Resources>
    <DataTemplate DataType="{x:Type vm:Page1ViewModel}">
        <v:Page1View />
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:Page3ViewModel}">
        <v:Page3View />
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:Page3ViewModel}">
        <v:Page3View />
    </DataTemplate>
</Window.Resources>

...

<TabControl ItemsSource="{Binding Pages}"
            DisplayMemberPath="Title">
</TabControl>

In the code above, the TabControl will pick the appropriate DataTemplate based on the item type, and will render it only when that item is selected.


EDIT 2: apparently you want to display the data of a single ViewModel on several pages. If you want the controls of each TabItem to lazily instantiated, you need to use the ContentTemplate property of each TabItem:

<TabControl>
    <TabItem Header="Page 1">
        <TabItem.ContentTemplate>
            <DataTemplate>
                <v:Page1View />
            </DataTemplate>
        </TabItem.ContentTemplate>
    </TabItem>
    <TabItem Header="Page 2">
        <TabItem.ContentTemplate>
            <DataTemplate>
                <v:Page2View />
            </DataTemplate>
        </TabItem.ContentTemplate>
    </TabItem>
    <TabItem Header="Page 3">
        <TabItem.ContentTemplate>
            <DataTemplate>
                <v:Page3View />
            </DataTemplate>
        </TabItem.ContentTemplate>
    </TabItem>
</TabControl>

I created this solution which works for our third party tabcontrol.

The idea is to "intercept" the datacontext when it is beeing set, save it for later and set the datacontext back to null. When the tabitem gets focus we then set the datacontext and the data will populate in the tab.

Implemented as a dependency property. Then simply set the property on the tabs that need to (do not set it on the tab that comes up as a default)

    #region SavedDataContext

    private static object GetSavedDataContext(TabItemEx tabItem)
    {
        return tabItem.GetValue(SavedDataContextProperty);
    }

    private static void SetSavedDataContext(TabItemEx tabItem, object value)
    {
        tabItem.SetValue(SavedDataContextProperty, value);
    }

    public static readonly DependencyProperty SavedDataContextProperty =
        DependencyProperty.RegisterAttached("SavedDataContext", typeof(object),
                                            typeof(Attach), new UIPropertyMetadata(null));

    #endregion

    #region LazyLoad

    public static bool GetLazyLoad(TabItemEx tabItem)
    {
        return (bool)tabItem.GetValue(LazyLoadProperty);
    }

    public static void SetLazyLoad(TabItemEx tabItem, bool value)
    {
        tabItem.SetValue(LazyLoadProperty, value);
    }

    private static readonly DependencyProperty LazyLoadProperty =
        DependencyProperty.RegisterAttached("LazyLoad", typeof(bool),
                                            typeof(Attach), new UIPropertyMetadata(false, LazyLoadPropertyChanged));

    private static void LazyLoadPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs eventArgs)
    {
        if ((bool)eventArgs.NewValue)
        {
            var tabItemEx = sender as TabItemEx;
            if (tabItemEx == null)
                return;

            tabItemEx.DataContextChanged += DataContextChanged;
            tabItemEx.GotFocus += TabGotFocus;
        }
    }


    #endregion

    private static void TabGotFocus(object sender, RoutedEventArgs e)
    {
        var tabItemEx = sender as TabItemEx;

        if (tabItemEx == null)
            return;

        tabItemEx.GotFocus -= TabGotFocus;
        tabItemEx.DataContext = GetSavedDataContext(tabItemEx);
        tabItemEx.IsSelected = true;
    }

    private static void DataContextChanged(object sender, DependencyPropertyChangedEventArgs eventArgs)
    {
        var tabItemEx = sender as TabItemEx;

        if (tabItemEx == null)
            return;

        SetSavedDataContext(tabItemEx, eventArgs.NewValue);

        tabItemEx.DataContextChanged -= DataContextChanged;
        tabItemEx.DataContext = null;
    }
Danylo Yelizarov

Marked as answer approach has one drawback - content of TabItem will be always re-rendered when selected. If it's critical - you can try this.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!