5

Brief

I've created a beautiful WindowChrome style to apply to my windows. When I add ContentControl to my style, however, the application enters break mode.

I've pieced together code from this youtube video, this article, this SO question and Microsoft's documentation and I've come up with the following code.

Note: The code below is all considered relevant since the application cannot run with either of these parts (yes I know it can run without the code-behind, but it's annoying having to stop the application from Visual Studio instead of the close button - which is also what I'm trying to accomplish). I've actually slimmed down the code below so that it's easier to work with.


Code

Window.xaml

<Style x:Key="TestWindow" TargetType="{x:Type Window}">
    <Setter Property="Background" Value="#FF222222"/>
    <Setter Property="BorderBrush" Value="WhiteSmoke"/>
    <Setter Property="BorderThickness" Value="5,30,5,5"/>
    <Setter Property="WindowChrome.WindowChrome">
        <Setter.Value>
            <WindowChrome CaptionHeight="20"
                          CornerRadius="0"
                          GlassFrameThickness="0,0,0,-1"
                          NonClientFrameEdges="None"
                          ResizeBorderThickness="5"
                          UseAeroCaptionButtons="True"/>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Window}">

                <Grid>

                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <AdornerDecorator>
                            <ContentPresenter/>
                        </AdornerDecorator>
                    </Border>

                    <DockPanel LastChildFill="True" VerticalAlignment="Top" Height="30">

                        <StackPanel DockPanel.Dock="Right"
                                    Orientation="Horizontal"
                                    VerticalAlignment="Center">
                            <Button x:Name="Button_Close"
                                    WindowChrome.IsHitTestVisibleInChrome="True"
                                    Width="{Binding ActualHeight, RelativeSource={RelativeSource Self}}"
                                    Click="CloseClick">
                                <ContentControl Template="{StaticResource Icon_Close}" Height="10"/>
                            </Button>
                        </StackPanel>

                        <StackPanel DockPanel.Dock="Left"
                                    Orientation="Horizontal"
                                    VerticalAlignment="Center">
                            <Image x:Name="PART_WindowCaptionIcon"
                                   Width="16"
                                   Height="16"
                                   Margin="0,0,6,0"
                                   Source="{TemplateBinding Icon}"/>
                            <TextBlock x:Name="PART_WindowCaptionText"
                                       Margin="6,0,0,0"
                                       Padding="0">
                                <Run BaselineAlignment="Center"
                                     Text="{TemplateBinding Title}"
                                     Foreground="Black"/>
                            </TextBlock>
                        </StackPanel>

                    </DockPanel>

                </Grid>

                <ControlTemplate.Triggers>
                    <Trigger SourceName="PART_WindowCaptionIcon" Property="Source" Value="{x:Null}">
                        <Setter TargetName="PART_WindowCaptionIcon" Property="Visibility" Value="Collapsed"/>
                        <Setter TargetName="PART_WindowCaptionText" Property="Margin" Value="5,0,0,0"/>
                    </Trigger>
                </ControlTemplate.Triggers>

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Icons.xaml

Window.xaml makes reference to this file for the ContentControl Template attribute values through App.xaml.

<ControlTemplate x:Key="Icon_Close">
    <Viewbox>
        <Polygon Points="357,35.7 321.3,0 178.5,142.8 35.7,0 0,35.7 142.8,178.5 0,321.3 35.7,357 178.5,214.2 321.3,357 357,321.3 214.2,178.5" Fill="Black"/>
    </Viewbox>
</ControlTemplate>

Window.xaml.cs

public partial class Window : ResourceDictionary
{
    public Window()
    {
        InitializeComponent();
    }

    private void CloseClick(object sender, RoutedEventArgs e)
    {
        var window = (System.Windows.Window)((FrameworkElement)sender).TemplatedParent;
        window.Close();
    }
}

Issue

When the line <ContentControl Template="{StaticResource Icon_Close}" Height="10"/> is present (line 38), the following message is received. When the same line is removed/commented out the application runs without entering break mode.

Message: The application is in break mode

Looking at the Output window I'm getting the following messages:

An unhandled exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll
Provide value on 'System.Windows.Markup.StaticResourceHolder' threw an exception.

Questions

This code worked when placed directly in the XAML code for the Window, but the moment I try to place it in the template it fails.

My questions are:

  1. Why does my application enter break mode when ContentControl is placed in the Window's template?
  2. How can I resolve this problem?
    • Please note that I must use my ControlTemplate from the Icons.xaml file and that the call to this content must remain in the window's Style (and not the window's actual xaml).
ctwheels
  • 21,901
  • 9
  • 42
  • 77
  • In the example link that you provided there is a class `WindowStyle` that derives from `ResourceDictionary` NOT `Window` class. – XAMlMAX Dec 15 '17 at 08:40
  • @XAMlMAX thanks for your reply! My class does actually inherit from `ResourceDictionary`. I just called the class `Window` instead of `WindowStyle` for testing purposes. I’ll likely be changing it to a potentially less conflicting class name once I get this to work, but for the time being I’m ok with the name conflicting with `System.Windows.Window`. – ctwheels Dec 15 '17 at 12:54
  • Do you *need* to replace the `ControlTemplate` of the `ContentControl`? Have you considered just setting the `Content` of the `ContentControl` to the `ViewBox` (It wouldn't be a `ControlTemplate` any more, just a `ViewBox` as a resource). – Bradley Uffner Dec 15 '17 at 15:19
  • I said that because Window in WPF has Content property but ResourceDictionary doesn't. That might be why it is picking up wrong class you see. partial class means that there is another declaration of that class somewhere else and because WPF uses reflection it might cause a conflict. – XAMlMAX Dec 15 '17 at 16:06
  • @BradleyUffner Thanks for that, it does allow me to actually clean up my resources (by using `Content` rather than `Template` and removing `ContentTemplate` from the `ResourceDictionary`). Unfortunately though, using `ContentControl` still causes the app to enter break mode even with your suggested changes. Is there an alternative to including an external `Viewbox` inside another element (i.e. Button) without using `ContentControl` that you're aware of? [That's the only thing I could find](https://stackoverflow.com/questions/19788073/how-to-use-xaml-graphic-inside-the-application-resource) – ctwheels Dec 15 '17 at 16:31
  • @XAMlMAX I changed the `xaml` and `xaml.cs` files to `WindowStyle` (insead of `Window`) and it's still entering break mode – ctwheels Dec 15 '17 at 16:32

1 Answers1

1

Brief

The issue was due to an incorrect order of my styles as per the answer on this question. I'm marking my question as a duplicate of that one, but felt I should share this as the answer in case it helps anyone else.

I love that Microsoft doesn't handle this with an appropriate exception and that you need to bang your head against a wall until either your head or the wall breaks.

Code

My App.xaml contains the following code in ResourceDictionary.MergedDictionaries

<ResourceDictionary Source="pack://application:,,,/MyProject;component/Window.xaml"/>
<ResourceDictionary Source="pack://application:,,,/MyProject;component/Icons.xaml"/>

I changed the order to the following

<ResourceDictionary Source="pack://application:,,,/MyProject;component/Icons.xaml"/>
<ResourceDictionary Source="pack://application:,,,/MyProject;component/Window.xaml"/>
ctwheels
  • 21,901
  • 9
  • 42
  • 77