【问题标题】:Setting WindowStartupLocation from ResourceDictionary throws XamlParseException从 ResourceDictionary 设置 WindowStartupLocation 会引发 XamlParseException
【发布时间】:2012-05-22 17:10:34
【问题描述】:

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

'设置属性'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 时,其他两个属性(SizeToContent 和ResizeMode)在引用样式的窗口上按预期设置:

<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 的错误/限制吗?

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

【问题讨论】:

    标签: c# wpf .net-4.0 resourcedictionary


    【解决方案1】:

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

    【讨论】:

    • 所以你可以直接从 XAML 设置 CLR(非依赖)属性(使用 &lt;Window WindowStartupLocation="CenterOwner" /&gt; 语法),但不能从资源字典中设置,对吗?
    • 不完全。您可以直接在 XAML 中设置属性,但您仍然可以使用资源字典,但不能使用样式。也就是说,以下工作: CenterOwner
    • 谢谢,很有帮助!不幸的是,我不能使用StaticResource,因为我需要从Window 中引用ResourceDictionary(我正在开发一个Office 插件,它不能为我提供WPF Application 类)。但是您的建议对于在 Windows 应用程序中集中默认样式非常有用。
    【解决方案2】:

    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>
    

    【讨论】:

    • 脱帽致敬!! ..这是一个正确的解决方案:)
    猜你喜欢
    • 1970-01-01
    • 2020-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 2012-03-30
    • 1970-01-01
    相关资源
    最近更新 更多