1

2つの本質的に同一のデータテンプレートが、暗黙的なスタイルリソースを解決する方法に関して完全に異なる動作をする状況があります。不整合により、私が取り組んでいる大規模なアプリケーションでアプリケーション全体のスタイルのリソースを処理することが困難になっています。

シナリオ。

AppStyles.xamlというスタンドアロンのxamlファイルにResourceDictionaryがあります。ButtonクラスとTextBlockクラスの両方の暗黙的なスタイルを定義します。

<!-- AppStyles.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
        <Setter Property="Padding" Value="10"/>
        <Setter Property="Background" Value="Red"/>
    </Style>

    <Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
        <Setter Property="Width" Value="300"/>
    </Style>

</ResourceDictionary>

私のMainWindow.xamlファイルは、AppStyles.xamlを独自のリソースにマージします。MainWindow.xamlには、それぞれが単純なviewmodelクラスにバインドされている2つのContentPresenterが含まれています。最初のContentPresenterによって使用されるデータテンプレートはMainWindow.xamlでインラインで宣言されたUserControlであり、2番目のContentPresenterによって使用されるデータテンプレートもインラインで宣言されますが、別のファイルで定義されたUserControlを参照します。両方のデータテンプレートで使用されるUserControlの実際の宣言は、それ以外は同じです。

<!-- MainWindow.xaml -->
<Window x:Class="Demo2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Demo2"
        Title="MainWindow" Height="350" Width="525"
        x:Name="_this">

    <Window.Resources>
        <ResourceDictionary>

            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/AppStyles.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <DataTemplate DataType="{x:Type local:TemplateVm1}">
                <UserControl>
                    <StackPanel>
                        <TextBlock Text="{Binding TextBlockValue}"/>
                        <Button Content="{Binding ButtonValue}"/>
                    </StackPanel>
                </UserControl>
            </DataTemplate>

            <DataTemplate DataType="{x:Type local:TemplateVm2}">
                <local:UserControl1/>
            </DataTemplate>

        </ResourceDictionary>
    </Window.Resources>


    <StackPanel>

        <ContentPresenter Content="{Binding ElementName=_this, Path=TemplateVm1}"/>

        <ContentPresenter Content="{Binding ElementName=_this, Path=TemplateVm2}"/>

    </StackPanel>
</Window>

問題。

問題は、2つのContentPresenterのレンダリングが完全に異なることです。両方のContentPresenterは、AppStyles.xamlのスタイルを使用してボタンをレンダリングしますが、最初のContentPresenterは暗黙のTextBlockスタイルを適用しませんが、2番目のContentPresenterは適用します。

私の期待は、コントロールから派生したコンポーネントのみがリソースを解決するために現在のテンプレートの外部を見るというWPFの動作のため、どちらのContentPresenterによっても表示されるテンプレートにTextBlockスタイルが適用されないことでした(そしてTextBlockはコントロールから派生しません)。

では、ここで何が起こっているのでしょうか。また、一貫して動作させるにはどうすればよいでしょうか。

例を完全にするために、ここにビューモデルとMainWindowコードの実装、および2番目のテンプレートで使用されるUserControlを示します。

// TemplateVm.cs
namespace Demo2
{
    public class TemplateVm1
    {
        public TemplateVm1()
        {
            TextBlockValue = "TextBlock in ContentPresenter1.";
            ButtonValue = "Button in ContentPresenter1";
        }

        public string TextBlockValue { get; private set; }
        public string ButtonValue { get; private set; }
    }

    public class TemplateVm2
    {
        public TemplateVm2()
        {
            TextBlockValue = "TextBlock in ContentPresenter2.";
            ButtonValue = "Button in ContentPresenter2";
        }

        public string TextBlockValue { get; private set; }
        public string ButtonValue { get; private set; }
    }
}
// MainWindow.xaml.cs
namespace Demo2
{
    using System.Windows;

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            TemplateVm1 = new TemplateVm1();
            TemplateVm2 = new TemplateVm2();
            InitializeComponent();
        }

        public TemplateVm1 TemplateVm1 { get; private set; }
        public TemplateVm2 TemplateVm2 { get; private set; }
    }
}
<!-- UserControl1.xaml -->
<UserControl x:Class="Demo2.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300">

    <StackPanel>
        <TextBlock Text="{Binding TextBlockValue}"/>
        <Button Content="{Binding ButtonValue}"/>
    </StackPanel>

</UserControl>
4

1 に答える 1

1

私の記憶が正しければ、WPFControlTemplatesは境界であると見なし、テンプレート内に暗黙的なスタイルを適用しません。

ただし、この規則には 1 つの例外があります。継承するものはすべて、Control暗黙的なスタイルを適用します。

a はButtonを継承しControlているため、暗黙的なスタイルが適用されます。ただし、 aはではなくTextBlockから継承するため、暗黙的なスタイルが自動的に適用されず、手動で追加する必要があります。FrameworkElementControl

TextBlockを aに切り替えると、から継承Labelされるため、暗黙的なスタイルが適用されることがわかります。LabelControl

別の方法として、あなたの内部にTextBlock別の暗黙的なスタイルを作成することで、暗黙的なスタイルを手動で適用できると思いますTextBlockUserControl.Resources

<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
于 2012-12-13T14:30:46.913 に答える