it-swarm.com.ru

Как установить стиль окна WPF по умолчанию в 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}

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

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

Спасибо!

62
NoizWaves

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

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

Если FrameworkElement не имеет явно заданного стиля, он всегда будет искать ресурс стиля, используя свой собственный тип в качестве ключа
- Программирование 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, но не пользовательский код позади.

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

45
Gishu

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

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

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

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

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

    <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. И, наконец, под Window, может быть, после Title, но перед последним Window '>':

    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 во всем решении! И тот же процесс может применяться к любым элементам управления, которые вы хотите иметь одинаковый вид, кнопки, что угодно.

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

Павел

20
Paul1307

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

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

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

8
Ray Booysen

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

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

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

3
STiLeTT

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

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

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

3
KroaX

Для тех, кто борется с решением проблемы: как можно автоматически применить собственный стиль ко всем типам, производным от 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);
    }
}
1
Arnie

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

0
Crossman