在 Prism(复合应用程序指南)中,如何将视图动态加载到 TabControl 中?

发布于 2024-07-14 15:57:47 字数 1595 浏览 2 评论 0原文

在 Prism v2 应用程序中,我定义了两个区域,每个区域都是 tabcontrol 中的一个 tabitem:

<UniformGrid Margin="10">
    <TabControl>
        <TabItem Header="First" Name="MainRegion" cal:RegionManager.RegionName="MainRegion"/>
        <TabItem Header="Second" Name="SecondRegion" cal:RegionManager.RegionName="SecondRegion"/>
    </TabControl>
</UniformGrid>

在引导程序中加载了两个模块,每个模块都向每个 tabitem 中注入一个视图:

protected override IModuleCatalog GetModuleCatalog()
{
    ModuleCatalog catalog = new ModuleCatalog();
    catalog.AddModule(typeof(SecondModule.SecondModule));
    catalog.AddModule(typeof(HelloWorldModule.HelloWorldModule));
    return catalog;
}

现在,当然,我想执行我之前的解耦魔法。继续阅读并取消注释其中一个模块,并看到其选项卡项根本不出现。 相反,仍然有两个TabItem,一个是空的。 这告诉我,我的应用程序仍然像过去糟糕的 WinForm 时代一样紧密耦合数据和 UI。

那么我需要在这里做什么来使其动态化,以便 UI 根据加载的模块动态更改,即这样我可以在引导程序中加载 10 个模块/视图,并且 TabControl 中会自动有 10 个 TabItem?

中间答案:

如果我只在 TabControl: 中创建一个区域,

<TabControl Name="MainRegion" cal:RegionManager.RegionName="MainRegion"/>

然后将两个控件加载到 MainRegion: 中,

        public void Initialize()
        {
            regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.SecondView));
        }
...
        public void Initialize()
        {
            regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.HelloWorldView));
        }

那么我会得到一个带有两个选项卡的 TabControl,每个选项卡中都有一个视图,这就是我想要的。

但 TabItem 标头未定义。 如何动态定义标头(例如,不在 XAML 中,而是在 View 类中动态定义标头)?

In a Prism v2 application, I define two regions, each a tabitem in a tabcontrol:

<UniformGrid Margin="10">
    <TabControl>
        <TabItem Header="First" Name="MainRegion" cal:RegionManager.RegionName="MainRegion"/>
        <TabItem Header="Second" Name="SecondRegion" cal:RegionManager.RegionName="SecondRegion"/>
    </TabControl>
</UniformGrid>

In the bootstrapper two modules are loaded and each injects a view into each of the tabitems:

protected override IModuleCatalog GetModuleCatalog()
{
    ModuleCatalog catalog = new ModuleCatalog();
    catalog.AddModule(typeof(SecondModule.SecondModule));
    catalog.AddModule(typeof(HelloWorldModule.HelloWorldModule));
    return catalog;
}

Now, of course, I want to perform the decoupling magic that I keep reading about and uncomment one of the modules and see its tab item not appear at all. Instead, on the contrary, there are still two TabItems and one is empty. This tells me that my application is still tightly coupling data and UI as in the bad old WinForm days.

So what do I need to do here to make this dynamic, so that the UI changes dynamically based on what modules are loaded, i.e. so that I could load 10 modules/views in my bootstrapper and there would automatically be 10 TabItems in the TabControl?

INTERMEDIATE ANSWER:

If I just make one region in a TabControl:

<TabControl Name="MainRegion" cal:RegionManager.RegionName="MainRegion"/>

and then load both controls into the MainRegion:

        public void Initialize()
        {
            regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.SecondView));
        }
...
        public void Initialize()
        {
            regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.HelloWorldView));
        }

then I get a TabControl with two tabs, each with a view in it, which is what I want.

But the TabItem headers are not defined. How do I dynamically define the header (e.g. not in the XAML but dynamically back in the View classes)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梅窗月明清似水 2024-07-21 15:57:47

这也有效:

public class View : UserControl
{

    public string ViewName { get; set; }

}

然后在 shell 中:

<Window.Resources>        
       <Style TargetType="{x:Type TabItem}" x:Key="TabItemRegionStyle">
                <Setter Property="Header" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.ViewName}" />
       </Style>
</Window.Resources>
    ...
<TabControl cal:RegionManager.RegionName="RightRegion" Width="Auto" Height="Auto" HorizontalAlignment="Stretch" Grid.Column="2" 
                x:Name="RightRegion" ItemContainerStyle="{StaticResource TabItemRegionStyle}" />

This works too:

public class View : UserControl
{

    public string ViewName { get; set; }

}

and then in the shell:

<Window.Resources>        
       <Style TargetType="{x:Type TabItem}" x:Key="TabItemRegionStyle">
                <Setter Property="Header" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.ViewName}" />
       </Style>
</Window.Resources>
    ...
<TabControl cal:RegionManager.RegionName="RightRegion" Width="Auto" Height="Auto" HorizontalAlignment="Stretch" Grid.Column="2" 
                x:Name="RightRegion" ItemContainerStyle="{StaticResource TabItemRegionStyle}" />
请远离我 2024-07-21 15:57:47

好的。

您可以删除视图上的 ViwewName 属性,并将 TabItem 值上的绑定更改为 Value="{Binding DataContext.HeaderInfo}" ...其中 HeaderInfo 是 DataContext 对象的属性 - 即选项卡项所包含的业务对象代表。 这更优雅一点。

Nice.

You can remove the ViwewName property on the view and change the binding on the TabItem value to be Value="{Binding DataContext.HeaderInfo}" ... where HeaderInfo is a property of your DataContext object - IE the business object which the Tab Item represents. This is a little more elegant.

欢你一世 2024-07-21 15:57:47

您的修改是在正确的轨道上。

我通常实现标题的方法是将对象而不是控件添加到该区域,并使用控件对其进行数据模板化。

该对象定义了一个属性(假设为 MyHeaderProperty),然后我用它来绑定到 TabControl 上的 ItemContainerStyle。

我不知道是否有一种方法可以实现这一目标,而无需诉诸这种技巧(中间对象和 DataTemplate)。

You are on the right track with your modification.

The way I usually achieve the header is by adding an object to the region instead of a control, and datatemplating it with the control.

This object defines a property (let's say MyHeaderProperty) which I then use to bind to using an ItemContainerStyle on the TabControl.

I do not know if there is a way to achieve that without resorting to that kind of trick (an intermediate object and a DataTemplate).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文