从ResourceDictionary设置WindowStartupLocation会抛出XamlParseException

时间:2012-05-15 08:03:43

标签: c# wpf .net-4.0 resourcedictionary

当我尝试通过WindowStartupLocation中的Setter设置ResourceDictionary属性时,我得到XamlParseException

  

'设置属性'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>

问题不在于使用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的错误/限制吗?

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

2 个答案:

答案 0 :(得分:10)

问题是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}" />

答案 1 :(得分: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;
    }
}

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

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

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

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