Как установить стиль WPF Window Style в app.xaml?

Я пытаюсь установить стиль по умолчанию для каждого окна в приложении WPF Windows в своем приложении app.xaml. Пока у меня это в app.xaml:

<Application.Resources>
    <ResourceDictionary>
        <Style x:Key="WindowStyle" TargetType="{x:Type Window}">
            <Setter Property="Background" Value="Blue" />
        </Style>
    </ResourceDictionary>
</Application.Resources>

Я могу заставить окно появляться с этим стилем при запуске приложения (но не является дизайнером VS), специально указав окну, чтобы использовать этот стиль с помощью:

Style="{DynamicResource WindowStyle}

Это работает, но не идеально. Итак, как я:

  • Все окна автоматически используют стиль (поэтому мне не нужно указывать его в каждом окне)?
  • Попросите дизайнера VS показать стиль?

Спасибо!

Ответ 1

Чтобы добавить к тому, что говорит Рэй:

Для стилей вам нужно указать ключ/идентификатор или указать TargetType.

Если элемент FrameworkElement не имеет явно указанный стиль, он будет всегда ищите ресурс стиля, используя свой собственный тип в качестве ключа
- Программирование WPF (Sells, Griffith)

Если вы укажете TargetType, все экземпляры этого типа будут применять стиль. Однако производные типы не будут... похоже. <Style TargetType="{x:Type Window}"> не будет работать для всех ваших пользовательских дериваций/окон. <Style TargetType="{x:Type local:MyWindow}"> будет применяться только к MyWindow. Таким образом, параметры

  • Используйте стиль Keyed, который вы указываете как свойство Style в каждом окне, которое вы хотите применить к стилю. Дизайнер покажет стилизованное окно.

.

    <Application.Resources>
        <Style x:Key="MyWindowStyle">
            <Setter Property="Control.Background" Value="PaleGreen"/>
            <Setter Property="Window.Title" Value="Styled Window"/>
        </Style>
    </Application.Resources> ...
    <Window x:Class="MyNS.MyWindow" Style="{StaticResource MyWindowStyleKey}">  ...
  • Или вы могли бы получить из пользовательского класса BaseWindow (который свои собственные причуды), где вы устанавливаете свойство Style во время Ctor/Initialization/Загрузите один раз. Тогда все производные будут автоматически применять стиль. Но дизайнер не обратит внимания на ваш стиль.. Вам нужно запустить приложение, чтобы увидеть применяемый стиль. Я предполагаю, что дизайнер просто запускает InitializeComponent (который является кодом, созданным автоматически/конструктором) поэтому XAML применяется, но не настраивается на основе кода.

Итак, я бы сказал, что явно указанные стили - наименее эффективные. Вы можете в любом случае изменить аспекты стиля по центру.

Ответ 2

Знайте это уже много лет, но поскольку вопрос все еще здесь...

  • Создайте словарь ресурсов в своем проекте (щелкните правой кнопкой мыши проект...)

    Я создам новую папку в проекте под названием "Активы" и  поместите в него "resourceDict.XAML".

  • Добавьте код в resourceDict.XAML:

    <Style x:Key="WindowStyle" Target Type="Window" >
         <Setter Property="Background" Value="Blue" />
    </Style>
    
  • В файле Project XAML добавьте следующее под окном:

    <Window.Resources>
        <ResourceDictionary>
            <!-- Believe it or not the next line fixes a bug MS acknowledges -->
            <Style TargetType="{x:Type Rectangle}" />
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Assets/resourceDict.XAML" />
            </ResourceDictionary.MergedDictionaries>
        <ResourceDictionary>
    </Window.Resources>
    

    ссылайтесь на следующий веб-сайт: Проблема со ссылкой на словарь ресурсов, который содержит объединенный словарь "Существует ошибка: если все ваши стили по умолчанию вложены в объединенные словари на три уровня глубиной (или глубже), верхний словарь не получает помечены, поэтому поиск пропускает его. Работа вокруг заключается в том, чтобы поместить стиль по умолчанию в что-то, что угодно, в корневом словаре". И это, кажется, надежно закрепляет вещи. Перейти фигурой...

  • И, наконец, под окном, возможно, после Title, но до окончательного Window ' > ':

    Style="{DynamicResource windowStyle}"
    
  • И вам нужно добавить код в шагах 3 и 4 в каждый проект, к которому вы хотите применить стиль.

  • Если вы хотите использовать фон градиента, а не сплошной цвет, добавьте следующий код в resourceDict.XAML:

    <LinearGradientBrush x:Key="windowGradientBackground" StartPoint="0,0"
            EndPoint="0,1" >
    <GradientStop Color= "AliceBlue" Offset="0" />
    <GradientStop Color= "Blue" Offset=".75" />
    </LinearGradientBrush>
    
  • И измените свой Style Setter для цвета фона:

    <Setter Property="Background" Value="{DynamicResource
            windowGradientBackground}" />
    

Шаги 3 и 4 должны быть повторены в каждом файле project.XAML, как описано выше, но эй, вы получаете единую Windows через решение! И тот же процесс может применяться к любым элементам управления, которым вы хотите иметь одинаковый внешний вид, кнопкам, что угодно.

Для тех, кто придет в это поздно, надеюсь, что это поможет, поскольку я уверен, что оригинальные плакаты получили это все, что было выдумано много лет назад.

Пол

Ответ 3

Дизайнер не работает, потому что вы указываете DynamicResource. Пожалуйста, измените это на StaticResource, и все будет хорошо.

Чтобы применить ко всем окнам, вы должны удалить x: Key из стиля. Установка TargetType неявно устанавливает x: Ключ к тому, что находится в TargetType. Однако в моих тестах это не работает, поэтому я просматриваю его.

Если я установил TargetType в x: Type TextBlock, конструктор отлично работает, похоже, что это окно, которое показывает другое поведение.

Ответ 4

Я исследовал это в течение нескольких дней и сделал это через конструктор моего собственного класса окон:

public class KWindow : Window
{
        public KWindow()
        {
            this.SetResourceReference(StyleProperty, typeof(KWindow));
        }

        static KWindow()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(KWindow), new FrameworkPropertyMetadata(typeof(KWindow)));

        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            // gets called finally
        }
}

Надеюсь, что это поможет кому-то

Ответ 5

Для тех, кто борется с решением проблемы: как я могу автоматически настраивать собственный стиль для всех моих производных типов Window? Ниже приведено решение, которое я придумал

ПРИМЕЧАНИЕ. Я действительно не хотел выводить из типа Window или вставлять XAML в каждое окно, чтобы принудительно обновить стиль и т.д. по причинам, характерным для моего проекта (потребители моего продукта нам использовали мою универсальную библиотеку стиля многократного использования и создать свой собственный макет/окна и т.д.), поэтому я был действительно мотивирован, чтобы понять, какое решение получило, что я готов жить с любыми побочными эффектами.

Нужно перебирать все созданные экземпляры окна и просто заставлять их использовать новый пользовательский стиль, который вы определили для типа Window. Это отлично подходит для окон, которые уже созданы, но когда создается окно или дочернее окно, он не будет знать, использовать новый/пользовательский тип, который был объявлен для его базового типа; тип ванильного окна. Поэтому лучше всего было бы использовать LostKeyBoardFocus в MainWindow, когда он теряет Focus в ChildWindow (IOW Когда дочернее окно было создано), а затем вызывает этот FixupWindowDerivedTypes().

Если у кого-то есть лучшее решение для "обнаружения", когда создается какой-либо тип производного от окна, и, таким образом, вызывается FixupWindowDerivedTypes(), что было бы замечательно. Может быть что-то полезное при обработке WM_WINDOWPOSCHANGING в этой области.

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

   public static void FixupWindowDerivedTypes()
    {
        foreach (Window window in Application.Current.Windows)
        {
           //May look strange but kindly inform each of your window derived types to actually use the default style for the window type

                    window.SetResourceReference(FrameworkElement.StyleProperty, DefaultStyleKeyRetriever.GetDefaultStyleKey(window));
                }
            }
        }
    }


//Great little post here from Jafa to retrieve a protected property like DefaultStyleKey without using reflection.
http://themechanicalbride.blogspot.com/2008/11/protected-dependency-properties-are-not.html

//Helper class to retrieve a protected property so we can set it
internal class DefaultStyleKeyRetriever : Control
{
    /// <summary>
    /// This method retrieves the default style key of a control.
    /// </summary>
    /// <param name="control">The control to retrieve the default style key 
    /// from.</param>
    /// <returns>The default style key of the control.</returns>
    public static object GetDefaultStyleKey(Control control)
    {
        return control.GetValue(Control.DefaultStyleKeyProperty);
    }
}

Ответ 6

Вы можете добавить этот код в файл App.xaml.cs:

        FrameworkElement.StyleProperty.OverrideMetadata(typeof(Window), new FrameworkPropertyMetadata
        {
            DefaultValue = Application.Current.FindResource(typeof(Window))
        });

После этого стиль, применяемый к типу Window, также применим ко всем типам, полученным из Window

Ответ 7

Учитывая ответ Gishu, я выяснил еще одно обходное решение. Но это может быть немного странно. Если вы используете шаблон MVVM, вы можете удалить код для вашего окна и x: Разметка класса в файле XAML. Таким образом, вы получите экземпляр окна или свое собственное окно, но не какой-то экземпляр класса "MainWindow", который является производным от класса "Window" и помечен как частичный. Я создаю VS-подобное окно, поэтому мне пришлось наследовать класс окон и расширить его функциональность. В этом случае можно будет сделать новый класс окон частичным, что позволило бы сделать код без наследования.

Ответ 8

  • вы сохраните все стили в одном файле xaml (пример design.xaml)

  • а затем вызовите этот файл (design.xaml) xaml на всех страницах, подобных этому.

Вроде:

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