Стиль WPF для базового окна не применяется в App.xaml, но находится в Themes/Generic.xaml

Я создаю класс базового окна для большинства моих окон. Очевидно, лучшим решением для этого был отдельный класс и стиль, который относится к нему.

Проблема в том, что <Style ../> я не применяюсь, когда он находится в App.Resources. То есть, если он определен во внешнем ResourceDictionary и объединен с ресурсами App.xaml, или локальным словарем и объединен, либо помещен в строку App.Resources. Тем не менее, <Style ../> применяется, когда он помещается в Themes/Generic.xaml.

Проблема может быть продемонстрирована без каких-либо специальных действий в базовом окне, кроме переопределения DefaultStyleKeyProperty.

Ниже ThemeWindow:

public class ThemeWindow : Window
{
    static ThemeWindow()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(ThemeWindow), new FrameworkPropertyMetadata(typeof(ThemeWindow)));
    }
}

Вот очень простой <Style ../>, который я пытаюсь применить (он делает фон Window красным, не более):

<Style TargetType="{x:Type testing:ThemeWindow}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type testing:ThemeWindow}">
                <Grid>
                    <Grid.Background>
                        <SolidColorBrush Color="Red"/>
                    </Grid.Background>
                    <AdornerDecorator>
                        <ContentPresenter />
                    </AdornerDecorator>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

MainWindow, который использует ThemeWindow, является просто следующим XAML:

<testing:ThemeWindow x:Class="Testing.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:testing="clr-namespace:Testing"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Content="Button" HorizontalAlignment="Left" Margin="125,83,0,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</testing:ThemeWindow>

Теперь, как указано, если вы поместите этот Style в свой собственный ResourceDictionary и включите его следующим образом:

<App.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/Themes/ThemeWindow.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</App.Resources>

.. он не работает. Если вы встраиваете стиль прямо в App.Resources, он не работает.

Единственная ситуация, в которой я могу найти работу, - это вызвать ResourceDictionary xaml Generic.xaml и поместить ее в каталог Themes/ приложения.

Мне интересно, почему это происходит.

Моя единственная теория заключается в том, что когда WPF видит тип управления, он перейдет к Themes и сканирует все ResourceDictionary для типа, затем вернется к Generic.xaml и загрузит его. Это не объясняет, почему он не будет загружаться, если <Style /> доступен в объединенном ResourceDictionary. Примечание, что он работает, если MergedDictionary помещен в Generic.xaml по понятным причинам.

Я отлично справляюсь с тем, чтобы объединить ResourceDictionary в Generic.xaml, если это то, что я должен сделать. Я просто хочу остановиться на технических подробностях относительно того, почему это должно быть так.

Скриншоты этого не работают/работают: Broken ImageWorking Image

Ответ 1

У меня есть простой способ обхода, который позволит вам установить свой стиль в приложении app.xaml.

Определите свой стиль в app.xaml следующим образом:

<Style x:Key="{x:Type testing:ThemeWindow}" TargetType="{x:Type testing:ThemeWindow}">

И измените ваше ThemWindow на это:

public class ThemeWindow : Window
{
    static ThemeWindow()
    {
        StyleProperty.OverrideMetadata(typeof(ThemeWindow), new FrameworkPropertyMetadata(GetDefautlStyle()));
    }

    private static Style GetDefautlStyle()
    {
        if (defaultStyle == null)
        {
            defaultStyle = Application.Current.FindResource(typeof(ThemeWindow)) as Style;
        }
        return defaultStyle;
    }

    private static Style defaultStyle = null;
}

На самом деле это не решает вопрос, но это позволит вам достичь того, что вам нужно!

РЕДАКТИРОВАТЬ: Глядя на DefaultStyleKey, он четко заявил, что он используется для поиска стиля темы. Это объясняет, почему он не найдет его в app.xaml или любом другом словаре. Он будет искать только в тематических словарях. Таким образом, вам нужно либо определить свой стиль в тематическом словаре, либо использовать свойство Style напрямую, как в приведенном выше примере.

Ответ 2

Я использую следующее решение, уже обсуждаемое в stackoverflow. это потребовало бы добавить в компонент нагрузки при загрузке приложения.

Обратитесь к решению