wpf 在 TabItem 中加载 UserControl

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9796174/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 23:20:01  来源:igfitidea点击:

Load UserControl in TabItem

wpfmvvmuser-controlstabitem

提问by PitAttack76

I have a Usercontrol(TabUserControl) which contains a TabControl. The Viewmodel of that UserControl loads ab Observable collection of TabItems. One od those items is another user control. When I just load text in the tabcontrol there is no problem, but how can I load the other user control into the tabitem of the TabUserControl. I'm using MVVM.

我有一个包含 TabControl 的 Usercontrol(TabUserControl)。该 UserControl 的 Viewmodel 加载 TabItems 的 ab Observable 集合。这些项目之一是另一个用户控件。当我只在 tabcontrol 中加载文本时,没有问题,但是如何将其他用户控件加载到 TabUserControl 的 tabitem 中。我正在使用 MVVM。

Here's my code:

这是我的代码:

public class TabItem
{
    public string Header { get; set; }
    public object Content { get; set; } // object to allow all sort of items??
}

The Viewmodel of the TabUserControl

TabUserControl 的视图模型

public class TabViewModel
{
    public ObservableCollection<TabItem> Tabs {get;set;}

    public TabViewModel()
    {
        Tabs = new ObservableCollection<TabItem>();
        //Tabs.Add(new TabItem { Header = "Overview", Content = new OverviewViewModel() }); How to load a usercontrol here if it's in the ItemCollection?
        Tabs.Add(new TabItem { Header = "Overview", Content = "Bla bla bla" });
        Tabs.Add(new TabItem { Header = "Two", Content = "Two's content" });
    }
}

And then the TabControl XAML:

然后是 TabControl XAML:

<TabControl x:Name="_tabControl"
            ItemsSource="{Binding Tabs}">
  <TabControl.ItemContainerStyle>
    <Style TargetType="TabItem">
      <Setter Property="Header"
              Value="{Binding Header}" />
      <Setter Property="Content"
              Value="{Binding Content}" />
    </Style>
  </TabControl.ItemContainerStyle>
</TabControl>

It works as long as I dont load the viewmodel of the usercontrol in the tabItems collection. how can I make the UserTabControl load on to the TabItem? The intention is that every tabitem will contain a usercontrol. Each usercontrol then does it's own thing.

只要我不在 tabItems 集合中加载用户控件的视图模型,它就可以工作。如何将 UserTabControl 加载到 TabItem?目的是每个 tabitem 都将包含一个用户控件。每个用户控件然后做它自己的事情。

Hope someone can help me as I am a WPF beginner. Thx!

希望有人可以帮助我,因为我是 WPF 初学者。谢谢!

回答by Rachel

Ideally, the TabControl.ItemsSourceshould be set to a collection of ViewModels, and DataTemplatesshould be used to tell the WPF to draw each ViewModelwith a specific UserControl.

理想情况下,TabControl.ItemsSource应该将 设置为 的集合ViewModels,并且DataTemplates应该用于告诉 WPFViewModel使用特定的UserControl.

This keeps between your business logic (ViewModels) completely separate from your UI (Views)

这使您的业务逻辑 ( ViewModels) 与您的 UI ( Views)完全分开

For example,

例如,

<TabControl x:Name="MyTabControl"
            ItemsSource="{Binding TabViewModels}"
            SelectedItem="{Binding SelectedTabViewModel}">

    <TabControl.Resources>
        <DataTemplate DataType="{x:Type my:ViewModelA}">
            <my:ViewAUserControl />
        </DataTemplate>
        <DataTemplate DataType="{x:Type my:ViewModelB}">
            <my:ViewBUserControl />
        </DataTemplate>
        <DataTemplate DataType="{x:Type my:ViewModelC}">
            <my:ViewCUserControl />
        </DataTemplate>
    </TabControl.Resources>

    <TabControl.ItemContainerStyle>
        <Style TargetType="TabItem">
            <Setter Property="Header" Value="{Binding Header}" />
        </Style>
    </TabControl.ItemContainerStyle>

</TabControl>

ViewModel containing TabControl's DataContext:

ViewModel 包含 TabControl 的 DataContext:

TabViewModels = new ObservableCollection<ITabViewModel>();
TabViewModels.Add(new ViewModelA { Header = "Tab A" });
TabViewModels.Add(new ViewModelB { Header = "Tab B" });
TabViewModels.Add(new ViewModelC { Header = "Tab C" });

SelectedTabViewModel = TabViewModels[0];

回答by Raviteja Somisetty

Thanks Rachel for your answer. But it enforces declaring the DataContext during compile time itself. Like you did, relating each of the Views to their respective ViewModels in the DataTemplate of TabControl. We can achieve dynamic View-ViewModel linking when move this out to ViewModel. Here's how:

感谢雷切尔的回答。但它强制在编译时本身声明 DataContext。像您一样,在 TabControl 的 DataTemplate 中将每个视图与它们各自的视图模型相关联。当把它移到 ViewModel 时,我们可以实现动态的 View-ViewModel 链接。就是这样:

XAML:

XAML:

<TabControl.ItemContainerStyle>
                <Style TargetType="TabItem">
                    <Setter Property="Header" Value="{Binding Header}" />
                    <Setter Property="Content" Value="{Binding Content}" />
                </Style>
            <TabControl.ItemContainerStyle>

VM:

虚拟机:

 public ObservableCollection<TabItem> TabItems { get; set; }
 public MainWindowViewModel()
        {
            TabItems = new ObservableCollection<TabItem>
            {
                new TabItem{Content = new TabAView() {DataContext = new TabAViewModel()}, Header = "Tab A"},
                new TabItem{Content = new TabBView(), Header = "Tab B"}
            };
        }

We can even make use of Action delegates to delay and invoke initialization of the TabItems only upon Tab SelectionChangedEvent. This achieves lot of memory saving if the UserControl Views have many UI elements.

我们甚至可以使用 Action 委托来延迟和仅在 Tab SelectionChangedEvent 时调用 TabItems 的初始化。如果 UserControl 视图有许多 UI 元素,这将节省大量内存。