Граница границы поля в окне не имеет никакого эффекта при использовании с WindowChrome

Я просматривал класс WindowChrome в библиотеке System.Windows.Shell (v 3.5.41019.1). Когда я пытаюсь создать шаблон Window, маржа элемента Border в шаблоне, похоже, не имеет эффекта:

<Window x:Class="WpfApplication7.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:shell="clr-namespace:Microsoft.Windows.Shell;assembly=Microsoft.Windows.Shell"
        Title="MainWindow" Height="350" Width="525" Style="{DynamicResource WindowStyle1}">
    <Window.Resources>
        <Style x:Key="WindowStyle1" TargetType="{x:Type Window}">
<!-- Here is the WindowChrome.-->
            <Setter Property="shell:WindowChrome.WindowChrome">
                <Setter.Value>
                    <shell:WindowChrome />
                </Setter.Value>
            </Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Window}">
<!-- And here is the Border. Its margin has no effect as far as I can tell.-->
                        <Border Margin="25" Background="Red">
                            <AdornerDecorator>
                                <ContentPresenter/>
                            </AdornerDecorator>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>

    </Grid>
</Window>

Как вы думаете, в чем причина? Мне интересно, потому что я видел, что некоторые люди используют что-то вроде *:

<Border x:Name="WindowBorder" Margin="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=WindowNonClientFrameThickness}" Background="Red">

Но поскольку это не влияет на мои тесты, что может быть для этого?

(*) Одним из мест, где он используется, является проект ModernUI на CodePlex.суб >

Изменить: Я тестировал это на Windows 7 с Aero on.

Изменить 2:. Все равно, что Aero выключен.

Ответ 1

Согласно MSDN, WindowChrome

Представляет объект, который описывает настройки для неклиентской области окна.

После прочтения образца MSDN и воспроизведения кода некоторое время я заметил, что ваш код должен выглядеть следующим образом из примера кода MSDN:

<Style x:Key="StandardStyle" TargetType="{x:Type local:MainWindow}">
<Setter Property="shell:WindowChrome.WindowChrome">
    <Setter.Value>
        <shell:WindowChrome />
    </Setter.Value>
</Setter>
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:MainWindow}">
            <!--Note there is a Grid as the root-->
            <Grid>
                <Border Background="White"
                        Margin="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=WindowNonClientFrameThickness}">
                    <ContentPresenter Content="{TemplateBinding Content}" />
                </Border>
                <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Title}" 
                           VerticalAlignment="Top" HorizontalAlignment="Left" 
                           Margin="36,8,0,0"/>
                <Image Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Icon}"
                       VerticalAlignment="Top" HorizontalAlignment="Left"
                       Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(shell:WindowChrome.WindowChrome).ResizeBorderThickness}" 
                       Width="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=SmallIconSize.Width}"
                       shell:WindowChrome.IsHitTestVisibleInChrome="True"/>
            </Grid>
        </ControlTemplate>
    </Setter.Value>
</Setter>

Обратите внимание, что в качестве корневого элемента есть Grid, который содержит несколько элементов для настройки NC окна.

UPDATE:

Вы можете заметить в примечании на странице MSDN, он содержит разделы:

WindowStyle.None

WindowChrome

Это два способа настройки внешнего вида окна приложения WPF.

Однако, задав для свойства Window.WindowStyle значение WindowStyle.None:

Это удаляет рамку неклиента из окна и оставляет только клиентской области, к которой вы можете применить собственный стиль. Однако, когда кадр без клиента удаляется, вы также теряете системные функции и которые он предоставляет, например, кнопки заголовка и окна изменение размера. Другим побочным эффектом является то, что окно будет охватывать Панель задач Windows, когда она максимизирована.

Затем вводится WindowChrome, чтобы включить настройку NC с помощью WPF:

Чтобы настроить окно, сохраняя стандартную функциональность, вы может использовать класс WindowChrome. Класс WindowChrome отделяет функциональность оконной рамы из визуальных элементов и позволяет контролировать границу между клиентскими и неклиентскими областями вашего окно приложения. Класс WindowChrome позволяет помещать содержимое WPF в оконной рамы путем расширения клиентской области для покрытия неклиента площадь. В то же время он сохраняет системное поведение через два невидимые области; области изменения размера и заголовка.

Итак, вернемся к вашему вопросу, шаблон, который вы нашли, должен быть скопирован из примера кода MSDN, но пропустил истинный корень Grid. Маржа на границе предназначена для предоставления некоторого пространства для ЧПУ. В образце кода MSDN ContenPreseter содержит только область клиента, а NC содержит Border, a TextBlock для заголовка окна и значок Image для окна.

Чтобы указать, установка WindowChrome позволяет настроить область ЧПУ окна в Window.Template.

Примечание: Пример образца кода MSDN кажется немного устаревшим в .Net 4.5, System.Windows.Shell.WindowChrome теперь находится в PresentationFramework.dll, поэтому код может выглядеть так:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525" Style="{DynamicResource WindowStyle1}" Icon="Icon1.ico">
<Window.Resources>
    <Style x:Key="WindowStyle1" TargetType="{x:Type Window}">
        <Setter Property="WindowChrome.WindowChrome">
            <Setter.Value>
                <WindowChrome />
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <Grid>
                        <Border Background="Red"
                        Margin="{Binding Source={x:Static SystemParameters.WindowNonClientFrameThickness}}">
                            <ContentPresenter Content="{TemplateBinding Content}" />
                        </Border>
                        <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Title}" 
                           VerticalAlignment="Top" HorizontalAlignment="Left" 
                           Margin="36,8,0,0"/>
                        <Image Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Icon}"
                       VerticalAlignment="Top" HorizontalAlignment="Left"
                       Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=WindowChrome.WindowChrome.ResizeBorderThickness}" 
                       Width="{Binding Source={x:Static SystemParameters.SmallIconWidth}}"
                       WindowChrome.IsHitTestVisibleInChrome="True"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Grid>
    <Button />
</Grid>

Ответ 2

Я думаю, что есть некоторые недоразумения в том, как вы пытаетесь установить границу. Вот объяснение класса WindowChrome, как указано в msdn

Класс WindowChrome отделяет функциональность оконного фрейма от визуальных элементов и позволяет управлять границей между клиентской и неклиентской областями вашего окна приложения. Класс WindowChrome позволяет помещать содержимое WPF в рамку окна, расширяя клиентскую область, чтобы охватить неклиентскую область. В то же время он сохраняет системное поведение через две невидимые области; области изменения размера и заголовка.

Итак, если вы пытаетесь настроить область NonClient для окна, это не Контент-презентатор, на который вы должны установить Border. Это клиентская область. Вместо этого в Шаблоне вы можете добавить свой XAML, кроме Content Presenter, чтобы определить свою область NonClient. Я просто попробовал простой код на основе вашего кода, и он сдвигает Title Property окна справа на значение 100. Вот код.

<Window x:Class="WPF_ToggleButton.ShellWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:shell="clr-namespace:Microsoft.Windows.Shell;assembly=Microsoft.Windows.Shell"
    Title="MainWindow" Height="350" Width="525" Style="{DynamicResource WindowStyle1}" 
    >

<Window.Resources>
    <Style x:Key="WindowStyle1" TargetType="{x:Type Window}">
        <Setter Property="shell:WindowChrome.WindowChrome">
            <Setter.Value>
                <shell:WindowChrome />
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <Grid>
                        <Border Background="Yellow">
                            <AdornerDecorator>
                                <ContentPresenter Content="{TemplateBinding Content}"/>
                            </AdornerDecorator>
                        </Border>
                        <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Title}" 
                           VerticalAlignment="Top" HorizontalAlignment="Left" 
                           Margin="100,0,0,0"/>
                    </Grid>                        
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Grid>
    <Border Margin="50" Background="AliceBlue"/>
</Grid>

Таким образом, вы можете иметь любые элементы в области NonClient, такие как изображение, представляющее вашу кнопку закрытия окна и т.д., используя код XAML. Последний элемент в окне определяет область клиента, которая передается в Content Presenter в шаблоне

Короче, если вы не хотите настраивать область клиента, используйте Content Presenter, тогда как если вы заинтересованы в изменении области NonClient Area, такой как панель заголовка, закройте значок изображения, а затем определите его в шаблоне.

Одно короткое наблюдение. Я думаю, что Margin не имеет никакого смысла для Window. Попробуйте установить его для обычного окна, и я думаю, что он не будет его уважать.