从ResourceDictionary设置WindowStartupLocation会抛出XamlParseException

Use*_*621 7 c# wpf .net-4.0 resourcedictionary

当我尝试WindowStartupLocation通过a Setter内设置属性时ResourceDictionary,我得到一个XamlParseException:

'Set property'System.Windows.Setter.Property'引发了异常.' 行号'x'和行位置'y'.

内部异常是ArgumentNullException:

值不能为空.参数名称:property.

我在资源字典中的风格是:

<Style TargetType="Window" x:Key="WindowStyle">
    <Setter Property="SizeToContent" Value="WidthAndHeight" />
    <Setter Property="ResizeMode" Value="CanMinimize" />
    <Setter Property="WindowStartupLocation" Value="CenterOwner" />
</Style>
Run Code Online (Sandbox Code Playgroud)

问题不在于使用ResourceDictionary,因为当我删除它时WindowStartupLocation,其他两个属性(SizeToContentResizeMode)在引用样式的窗口上按预期设置:

<Window x:Class="WpfApplication1.MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Style="{DynamicResource WindowStyle}">
    <Window.Resources>
        <ResourceDictionary Source="MyResourceDictionary.xaml" />
    </Window.Resources>
</Window>
Run Code Online (Sandbox Code Playgroud)

有没有遇到过这个?它是WPF的错误/限制吗?

PS我知道这个问题类似于资源字典中的Window Startup Location,但是在其他问题中没有提供足够的信息,后来仍未解决.

And*_*nes 11

问题是WindowStartupLocation不是DependencyProperty,因此您无法在样式设置器中设置它.看看ILSpy,Setter打来电话

CheckValidProperty(DependencyProperty property)
Run Code Online (Sandbox Code Playgroud)

并抛出NullArgumentException.

由于WindowStartupLocation只是一个CLR属性,因此无法以这种方式设置.

Edit:回应评论.你仍然可以使用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}" />
Run Code Online (Sandbox Code Playgroud)


Ana*_*aev 6

WindowStartupLocation是CLR属性,可以在以下位置看到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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在样式setter中只能指定依赖属性.有两种方法可以解决这个问题:

  • 继承类Window,并使用依赖项属性创建您的类WindowStartupLocation

  • 根据WindowStartupLocationPropertyChanged 创建附加属性类型并定义逻辑

第一种方法很麻烦,因为有必要为一个属性重新定义类.第二种方法是首选,并将附加行为,但我会打电话PropertyExtension.

这是完整的代码:

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用示例:

<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>
Run Code Online (Sandbox Code Playgroud)