Setting WindowStartupLocation from ResourceDictionary throws XamlParseException

喜夏-厌秋 提交于 2019-11-29 13:42:31
Andrew Jones

The problem is that WindowStartupLocation is not a DependencyProperty so you can't set it in the style setter. Looking in ILSpy the Setter calls

CheckValidProperty(DependencyProperty property)

and throws a NullArgumentException.

As WindowStartupLocation is just a CLR property, it can't be set in this way.

Edit: To respond to the comment. You can still use a ResourceDictionary:

<Application.Resources>
    <ResourceDictionary>
        <Style x:Key="WindowStyle" TargetType="Window">
            <Setter Property="SizeToContent" Value="WidthAndHeight" />
            <Setter Property="ResizeMode" Value="CanMinimize" />
        </Style>
        <WindowStartupLocation x:Key="WSL">CenterOwner</WindowStartupLocation>
    </ResourceDictionary>
</Application.Resources>

<Window x:Class="WpfApplication7.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"            
        WindowStartupLocation="{StaticResource WSL}"
        Style="{StaticResource WindowStyle}" />

WindowStartupLocation is a CLR property, this can be seen in ILSpy:

[DefaultValue(WindowStartupLocation.Manual)]
public WindowStartupLocation WindowStartupLocation
{
    get
    {
        this.VerifyContextAndObjectState();
        this.VerifyApiSupported();
        return this._windowStartupLocation;
    }

    set
    {
        this.VerifyContextAndObjectState();
        this.VerifyApiSupported();

        if (!Window.IsValidWindowStartupLocation(value))
        {
            throw new InvalidEnumArgumentException("value", (int)value, typeof(WindowStartupLocation));
        }

        this._windowStartupLocation = value;
    }
}

In the style setters can only be specified dependency property. There are two ways to solve this problem:

  • inherit class Window, and create your class with a dependency property WindowStartupLocation

  • create an attached property type depending WindowStartupLocation and define the logic in the PropertyChanged

The first method is cumbersome, because it is necessary to redefine the class for one property. The second method is preferred, and will be attached behavior, but I'll call PropertyExtension.

Here is the complete code:

namespace YourProject.PropertiesExtension
{
    public static class WindowExt
    {
        public static readonly DependencyProperty WindowStartupLocationProperty;

        public static void SetWindowStartupLocation(DependencyObject DepObject, WindowStartupLocation value)
        {
            DepObject.SetValue(WindowStartupLocationProperty, value);
        }

        public static WindowStartupLocation GetWindowStartupLocation(DependencyObject DepObject)
        {
            return (WindowStartupLocation)DepObject.GetValue(WindowStartupLocationProperty);
        }

        static WindowExt() 
        {            
            WindowStartupLocationProperty = DependencyProperty.RegisterAttached("WindowStartupLocation",
                                                      typeof(WindowStartupLocation),
                                                      typeof(WindowExt),
                                                      new UIPropertyMetadata(WindowStartupLocation.Manual, OnWindowStartupLocationChanged));
        }

        private static void OnWindowStartupLocationChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            Window window = sender as Window; 

            if (window != null) 
            {
                window.WindowStartupLocation = GetWindowStartupLocation(window);
            }
        }
    }
}

Example of using:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:PropertiesExtension="clr-namespace:YourProject.PropertiesExtension">

    <Style TargetType="{x:Type Window}">            
        <Setter Property="PropertiesExtension:WindowExt.WindowStartupLocation" Value="CenterScreen" />
        <Setter Property="Width" Value="723" />
        <Setter Property="Height" Value="653" />
        <Setter Property="Title" Value="MainWindow title string" />    
    </Style>
</ResourceDictionary>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!