如何在WPF中创建模板窗口?

23

我正在开发一个应用程序,它将有很多窗口,每个窗口的基本布局相同:

  1. 一个主窗口
  2. 在左上角有一个标志
  3. 一个标题块
  4. 底部有一个状态显示器
  5. 一个用于窗口特定控件的区域。

目前,我必须在每个窗口中重新创建此结构。理想情况下,我希望将这个布局编码到单个位置,可能是为了方便使用而编写的自定义窗口子类。是否有人对如何入手或类似问题有过经验?

4个回答

37

您可以创建一个新的ControlTemplate,将其目标设置为窗口,以实现以下内容。

<ControlTemplate x:Key="WindowControlTemplate1" TargetType="{x:Type Window}">
    <Border 
        Background="{TemplateBinding Background}" 
        BorderBrush="{TemplateBinding BorderBrush}" 
        BorderThickness="{TemplateBinding BorderThickness}"
        >
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="0.93*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.21*"/>
                <ColumnDefinition Width="0.79*"/>
            </Grid.ColumnDefinitions>

            <ContentPresenter 
                Grid.ColumnSpan="2" 
                Grid.Row="1" 
                Content="{TemplateBinding Content}" 
                ContentTemplate="{TemplateBinding ContentTemplate}"
                />
            <ResizeGrip 
                HorizontalAlignment="Right" 
                x:Name="WindowResizeGrip" 
                VerticalAlignment="Bottom" 
                IsTabStop="False" 
                Visibility="Collapsed" 
                Grid.Column="1" 
                Grid.Row="2"
                />
            <TextBlock Text="My Logo" />
            <TextBlock Grid.Column="1" Text="My Title"/>
            <StatusBar Height="20" Grid.ColumnSpan="2" Grid.Row="2"/>
        </Grid>
    </Border>

    <ControlTemplate.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="ResizeMode" Value="CanResizeWithGrip"/>
                <Condition Property="WindowState" Value="Normal"/>
            </MultiTrigger.Conditions>
            <Setter Property="Visibility" TargetName="WindowResizeGrip" Value="Visible"/>
        </MultiTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

我想自定义窗口的非客户区域。当我尝试自定义模板时,我只能更改客户区域的视觉表示。我想在标题栏中添加内容控件或其他控件。 - Shameel Mohamed

6
如果您勇敢地进行大型架构转变,您可以考虑来自Microsoft的模式和实践团队的CompositeWPF(以前的代号为Prism)。
对您感兴趣的是在外壳(即窗口)中定义“区域”,然后使用视图填充这些区域的能力。它使用模型-视图-表示器模式,允许从与模型分开独立开发的“视图”中轻松地重新定位,因为外壳仅定义区域,而不直接耦合放置在其中的内容。主要是帮助解耦外壳和视图以及视图之间,并使单元测试更加容易...等等。
这是一个很大的飞跃,开始时会减慢您的速度,尽管您的情况是CompositeWPF旨在解决的应用程序类型之一。
作为CompositeWPF的一部分,您需要采用各种可能会使新手困惑的模式,例如UnityContainer、控制反转、MVP(或模型/视图/视图模型)和依赖注入。
我可以记得当我第一次开始使用示例应用程序时感到困惑,因为根本不清楚某些视图是如何创建的!Unity容器将通过魔法实例化对象并调用参数化构造函数。
CompositeWPF是一个优雅的解决方案,但并不简单或直接。在我的上一个项目中使用了CompositeWPF后,我打算在下一个适当的应用程序中再次使用它。

感谢您对CompositeWPF的详细介绍。我下载了WPF的复合应用程序指南,但更加困惑了。我想知道是否有一些简单的例子可以让新手学习? - Picflight
@Picflight:这是一篇关于DevX的Brian Noyes文章的链接http://www.devx.com/codemag/Article/40165/1763。在任何你可以获取示例代码的地方,使用调试器来帮助你学习事物的工作原理。在类的构造函数上设置断点,并沿着调用堆栈向上走,以了解其工作方式。 - Rhys

2
最简单的方法是为窗口专用控件创建WPF“页面”,并在主窗口中放置一个“Frame”框架。 通过这种方式,您甚至可以创建漂亮的导航。

-6

为什么你要使用“许多窗口”呢?为什么不只用一个带选项卡控件的窗口?或者只有一个窗口和用户控件?

无论如何,回答你的问题,用户控件是实现你想要的功能的一种方式。

创建一个新的Window类,并使其具有“Childrens”属性,该属性允许将对象嵌入到您想要放置“特定于窗口的控件”的停靠面板中。

当您启动新的窗口时,实例化窗口类型和具有特定控件的用户控件,将用户控件添加到窗口的Children属性中,然后显示窗口。您甚至可以在此时绑定事件处理程序、DataContext等。


1
为什么会有这么多踩?在我看来,这似乎是一个合理的问题,也许不是最理想的答案,但对于正确的情况来说绝对值得考虑。 - MikeKulls
1
因为它虽然提供了解决方案,但并没有真正回答问题。此外,这是一种高度蛮力的解决方案。实际上,我会将其描述为WINFORMS方法来解决它,而非被选答案中的WPF方法。 - Stephen Wrighton
也许你过于关注“带有选项卡控件的单个窗口”这一点了?在正确的情况下,具有可互换用户控件的单个窗口是完全有效的解决方案。它是唯一的解决方案,可以避免代码重复,如果您有多个窗口,则某种形式的代码(无论多小)需要在每个窗口中复制。如果需要进行更改,则需要在多个位置更改该代码。这不是一个决定性因素,但肯定值得考虑。 - MikeKulls
我收回之前的说法。一个带有选项卡控件的单个窗口也是完全有效的解决方案。动态选项卡控件如今非常流行,因为它们提供了一种更加用户友好的在窗口之间导航的方法。我认为人们之所以对此进行负投票,是因为他们认为Stephen指的是一个固定选项卡数量的选项卡控件。 - MikeKulls
多个监视器,您可以从应用程序和其他来源(如多窗口Web浏览器、其他公司应用程序等)跟踪、比较和管理实时信息。您需要能够移动和调整各种数据的窗口,而不是将它们锁定在单个窗口中或将该窗口扩展到阻止其他信息的多个监视器上。我没有投反对票,尽管我认为这是因为过于强调“为什么需要很多窗口”,应该只是提醒/建议避免做一个过度界面的多接口应用程序,其中子控件就足够了。 - Karl Stephen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接