Как установить стиль окна WPF по умолчанию в app.xaml? - PullRequest
62 голосов
/ 11 января 2009

Я пытаюсь установить стиль по умолчанию для каждого окна в моем приложении 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}

Это работает, но не идеально. Так как же мне:

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

Спасибо!

Ответы [ 8 ]

45 голосов
/ 20 января 2009

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

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

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

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

  • Используйте Keyed Style, который вы указываете в качестве свойства 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 / Load один раз. Все деривации будут автоматически применены к стилю. Но дизайнер не заметит ваш стиль Вам нужно запустить свое приложение, чтобы увидеть применяемый стиль ... Я предполагаю, что дизайнер просто запускает InitializeComponent (который является сгенерированным автоматически / дизайнером кодом) XAML применяется, но не пользовательский код-позади.

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

20 голосов
/ 28 марта 2012

Знайте, что это годы спустя, но так как вопрос все еще здесь ...

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

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

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

    <Style x:Key="WindowStyle" Target Type="Window" >
         <Setter Property="Background" Value="Blue" />
    </Style>
    
  3. В вашем файле 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>
    

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

  4. И, наконец, под окном, может быть, после заголовка, но перед окончательным окном '>':

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

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

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

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

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

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

Пол

8 голосов
/ 11 января 2009

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

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

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

3 голосов
/ 31 января 2017

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

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

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

3 голосов
/ 25 февраля 2015

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

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
        }
}

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

1 голос
/ 10 мая 2013

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

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

Необходимо пройти через все экземпляры окон и просто заставить их использовать новый пользовательский стиль, который вы определили для типа окна. Это прекрасно работает для окон, которые уже открыты, но когда создается экземпляр окна или дочернего окна, он не будет знать, использовать ли новый / пользовательский тип, который был объявлен для его базового типа; Тип ванильного окна. Поэтому лучшее, что я мог придумать, - это использовать 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);
    }
}
0 голосов
/ 02 февраля 2014

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

0 голосов
/ 18 ноября 2013
  1. Вы сохраните все стили в одном файле xaml (пример design.xaml)

  2. и затем назовите этот (design.xaml) файл xaml на всех страницах следующим образом:

Как:

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