10

当我尝试通过 a中的 a设置WindowStartupLocation属性时,我得到一个:SetterResourceDictionaryXamlParseException

'设置属性'System.Windows.Setter.Property' 引发异常。行号“x”和行位置“y”。

内部异常是ArgumentNullException

值不能为空。参数名称:属性。

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

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

问题不在于使用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>

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

PS我知道这个问题类似于Window Startup Location from resource dictionary,但在另一个问题中没有提供足够的信息,随后仍未解决。

4

2 回答 2

14

问题是 WindowStartupLocation 不是 DependencyProperty 所以你不能在样式设置器中设置它。查看 ILSpy 的 Setter 调用

CheckValidProperty(DependencyProperty property)

并抛出 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}" />
于 2012-05-15T08:27:42.857 回答
7

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

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

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

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

第一种方法比较麻烦,因为需要为一个属性重新定义类。第二种方法是首选,并且会附加行为,但我会调用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);
            }
        }
    }
}

使用示例:

<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>
于 2014-01-17T05:31:15.287 回答