【问题标题】:change the content of a window control template in WPF在 WPF 中更改窗口控件模板的内容
【发布时间】:2014-03-15 07:22:27
【问题描述】:

我有一个包含多个窗口(作为对话框)的应用程序,其中大多数具有相同的控件(左侧是扩展器,右侧是数据网格)。

开发此类应用程序的最佳方式是什么?我想过像这样为窗口编写一个控件模板:

<ControlTemplate x:Key="WindowControlTemplate" TargetType="{x:Type Window}">
    <Border Background="{TemplateBinding Background}" 
            BorderBrush="{TemplateBinding BorderBrush}" 
            BorderThickness="{TemplateBinding BorderThickness}" >
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.20*"/>
                <ColumnDefinition Width="0.80*"/>
            </Grid.ColumnDefinitions>

            <Expander ExpandDirection="Right" IsExpanded="True" Grid.Column="0">
                <Expander.Header>
                    <TextBlock FontSize="14" Text="Control Panel" Background="Gray">
                        <TextBlock.LayoutTransform>
                            <RotateTransform Angle="90"/>
                        </TextBlock.LayoutTransform>
                    </TextBlock>
                </Expander.Header>
                <Grid >
                    <Grid.Background>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                            <GradientStop Color="#FFBFB5B5" Offset="0"/>
                            <GradientStop Color="#FFC97A7A" Offset="1"/>
                        </LinearGradientBrush>
                    </Grid.Background>
                </Grid>
            </Expander>

            <DataGrid Grid.Column="2">
            </DataGrid>

        </Grid>
    </Border>

</ControlTemplate>

然后我用这个模板定义了一个新窗口,但我不知道如何将控件添加到扩展器以及如何将数据绑定到数据网格。

【问题讨论】:

    标签: wpf controltemplate


    【解决方案1】:

    这样说就很简单了:

    1. 您不需要多个窗口或多个控件来实现此目的。
    2. 只需创建 1 个包含所有必需部件的窗口。
    3. 将您的DataTemplates 写在每个部分的Resources 中。
    4. 如果您按照以下说明进行操作,您的视图的不同部分可以找到正确的模板。

    在这种方法中,在 Expander 或 ContentPresenter 的资源中使用的 DataTemplate 将根据DataContext 的正确类型自动选择和设置。请注意,我必须从这些 DataTemplate 和 Style 中删除 x:Key,后者用于设置数据网格的公共属性。

    <Grid>
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="0.20*"/>
             <ColumnDefinition Width="0.80*"/>
         </Grid.ColumnDefinitions>
    
         <Expander ExpandDirection="Right" IsExpanded="True" Grid.Column="0">
             <Expander.Resources>
                 <DataTemplate DataType="{x:Type vm:MyType1}">
                    <Grid>
                        <Grid.Background>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#FFBFB5B5" Offset="0"/>
                                <GradientStop Color="#FFC97A7A" Offset="1"/>
                            </LinearGradientBrush>
                        </Grid.Background>
                    </Grid>
                 </DataTemplate>
                 <DataTemplate DataType="{x:Type vm:MyType2}">
                     <Grid>
                         <Grid.Background>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#FAAA" Offset="0"/>
                                <GradientStop Color="#F0F0" Offset="1"/>
                            </LinearGradientBrush>
                         </Grid.Background>
                     </Grid>
                 </DataTemplate>
             </Expander.Resources>
    
             <Expander.Header> 
                 <TextBlock FontSize="14" Text="Control Panel" Background="Gray">
                      <TextBlock.LayoutTransform>
                          <RotateTransform Angle="90"/>
                      </TextBlock.LayoutTransform>
                 </TextBlock>
             </Expander.Header>
    
             <ContentPresenter Content="{Binding}">
         </Expander>
    
         <ContentPresenter Content="{Binding}">
             <ContentPresenter.Resources>
                 <DataTemplate DataType="{x:Type vm:MyType1}">
                    <DataGrid ItemsSource="{Binding MyList1}">
                       <DataGrid.Columns>
                          <DataGridTextColumn Binding="{Binding MyProperty1}"/>
                       </DataGrid.Columns>
                    </DataGrid>
                 </DataTemplate>
    
                 <DataTemplate DataType="{x:Type vm:MyType2}">
                    <DataGrid ItemsSource="{Binding MyList2}">
                       <DataGrid.Columns>
                          <DataGridTextColumn Binding="{Binding MyProperty2}"/>
                       </DataGrid.Columns>
                    </DataGrid>
                 </DataTemplate>
             </ContentPresenter.Resources>
         </ContentPresenter>
    </Grid>
    

    在这个例子中,我使用了两个视图模型,名为 MyType1(有一个名为 MyList1 的列表,每个元素都是视图模型本身,并有一个名为 MyProperty1 的属性)和 MyType2(与 MyType1 相同,但具有 MyList2 和 MyProperty2)

    您可以打开如下窗口:

    Window w1 = new Window();
    w1.DataContext = new MyType1();
    w1.Show();
    

    注意:

    另外,为了避免 DataGrid 代码中的冗余,您可以在ContentPresenter.Resources 中添加一个不带x:Key 的样式来设置DataGrid 的一些属性。这些属性将应用于作为ContentPresenter 一部分的任何DataGrid

         <ContentPresenter Content="{Binding}">
             <ContentPresenter.Resources>
                <Style TargetType="{x:Type DataGrid}">
                    <Setter Property="AutoGenerateColumns" Value="False"/>
                </Style>
                <DataTemplate DataType="{x:Type vm:MyType1}">
                    <DataGrid ItemsSource="{Binding MyList1}">
                    ...
                 ...
              ...
    

    注意:

    错误代码:

        <DataGrid ItemsSource="{Binding Items}">
            <DataGrid.Resources>
                <Style TargetType="{x:Type DataGrid}">
                    <Setter Property="DataGrid.Columns">
                        <Setter.Value>
                            <DataGridTextColumn Binding="{Binding}"/>
                        </Setter.Value>
                    </Setter>
                </Style>
            </DataGrid.Resources>
        </DataGrid>
    

    我没有使用上面的代码来概括DataGrid的原因是DataGrid.Columns是一个附加属性,不能在样式的setter中设置。但如果所有对话框中的数据网格列都相同,您可以对数据网格使用更简单的方法。

    这样,您必须为列表及其元素的属性设置一个通用名称:

        <DataGrid ItemsSource="{Binding MyCommonList}">
           <DataGrid.Columns>
              <DataGridTextColumn Binding="{Binding MyCommonProperty}"/>
           </DataGrid.Columns>
        </DataGrid>
    

    【讨论】:

    • 虽然这行得通。这完全是多余的。 ContentPresenter 已经在资源中搜索具有正确 DataType 标签的数据模板。
    • 此方法可确保即使存在一种数据类型的两个模板,也会选择正确的模板。由于基础设施可用,因此可以简单地将所需的逻辑添加到 templateSelector 的代码并使其更具可定制性。
    • 但是你说得对,我添加了一条评论来突出模板选择器在这种情况下的用途。
    • 对不起,我没看懂答案。我想使用我的模板创建 10 多个窗口(对话框),并且在每个窗口中我需要向扩展器添加一些控件,并将网格绑定到一些数据。
    • 抱歉回复太晚了。请看一下更改后的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多