为什么 x:Array 元素会导致其后的任何 x:Shared 属性被忽略? [英] Why does an x:Array element cause any x:Shared attribute following it to be ignored?
问题描述
我怀疑存在 XAML 编译器和/或 WPF 错误,但我想确保我在这里没有做错任何事情(除了信任 XAML 编译器和/或 WPF,即 :)).
I suspect a XAML compiler and/or WPF bug, but I want to make sure I haven't done something wrong here (other than trusting the XAML compiler and/or WPF, that is :) ).
考虑使用以下 XAML 来获取将重现该问题的最小 WPF 程序:
Consider the following XAML for a minimal WPF program that will reproduce the problem:
<Window x:Class="TestxSharedMenuItem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<x:Array x:Key="menuItemValues1" Type="{x:Type s:String}">
<s:String>value #1</s:String>
<s:String>value #2</s:String>
<s:String>value #3</s:String>
</x:Array>
<MenuItem x:Key="menuItem1" x:Shared="False"
ItemsSource="{StaticResource menuItemValues1}"
Header="Shared menu item"/>
</Window.Resources>
<StackPanel>
<Menu HorizontalAlignment="Left" VerticalAlignment="Top">
<StaticResource ResourceKey="menuItem1"/>
<StaticResource ResourceKey="menuItem1"/>
</Menu>
</StackPanel>
</Window>
程序运行时,WPF抛出异常:
When the program is run, WPF throws an exception:
XamlParseException
:向System.Windows.Controls.ItemCollection"类型的集合添加值引发异常.行号20"和行位置23".
XamlParseException
: 'Add value to collection of type 'System.Windows.Controls.ItemCollection' threw an exception.' Line number '20' and line position '23'.
InnerException
是:
InvalidOperationException
:元素已经有一个逻辑父元素.它必须先与旧父级分离,然后才能附加到新父级.
InvalidOperationException
: Element already has a logical parent. It must be detached from the old parent before it is attached to a new one.
当然,如果人们试图在多个地方使用相同的控件,这正是人们所期望看到的.但是使用 x:Shared="False"
属性 应该 导致每次检索时返回 MenuItem
资源对象的新实例,避免这个问题.
This is, of course, exactly what one would expect to see if one were trying to use the same control in multiple places. But using the x:Shared="False"
attribute should be causing a new instance of the MenuItem
resource object to be returned each time it's retrieved, avoiding that problem.
出于某种原因,在 MenuItem
元素之前添加 x:Array
元素会导致 x:Shared
属性被忽略,从而导致引用资源时共享单个 MenuItem
元素,因此导致异常.
For some reason, having the x:Array
element before the MenuItem
element causes the x:Shared
attribute to be ignored, resulting in a single MenuItem
element being shared when the resource is referenced, and so causing the exception.
其他观察:
- 将
x:Shared
添加到x:Array
元素没有帮助(它不应该,但我认为值得检查). MenuItem
元素是否实际引用了x:Array
元素并不重要.仅存在x:Array
元素就足以导致问题.- 上面的示例使用
MenuItem
,因为这是我遇到问题的地方,但其他控件类型也会出现此问题.
- Adding
x:Shared
to thex:Array
element doesn't help (it shouldn't, but I figured it was worth checking). - It does not matter whether the
MenuItem
element is actually referencing thex:Array
element or not. The mere presence of thex:Array
element is sufficient to cause the problem. - The example above uses
MenuItem
because this is where I ran across the problem, but the issue happens for other control types too.
变通方法包括:
- 将
x:Array
移动到不同的ResourceDictionary
(例如在App.xaml
中).它的存在似乎只影响找到它的字典声明.(这样做可能可行,也可能不可行,具体取决于需要声明非共享控制资源的位置). - 移动
x:Array
在字典声明中出现在非共享控制资源声明的后面.当然,如果非共享控制资源需要x:Array
元素,这也无济于事. - 声明
x:Array
与非共享控件内联,而不是作为单独的资源.这解决了前两个变通方法中可能存在的依赖性问题,但当然会阻止x:Array
与其他可能使用它的字典条目共享,并加剧了围绕非可共享的控制元素(即,您不仅拥有控制元素的多个副本,还获得它所依赖的数组的多个副本).例如:
- Moving the
x:Array
to a differentResourceDictionary
(e.g. inApp.xaml
). Its presence appears to only affect the dictionary declaration in which it's found. (Doing so may or may not be feasible, depending on where the non-shared control resource needs to be declared). - Moving the
x:Array
to appear later in the dictionary declaration than the non-shared control resource's declaration. Of course, if the non-shared control resource requires thex:Array
element, this doesn't help. - Declaring the
x:Array
inline with the non-shared control rather than as a separate resource. This solves the dependency issues that might exist in the previous two work-arounds, but of course prevents sharing of thex:Array
with other dictionary entries that could use it, and exacerbates the issues surrounding the non-sharable control element (i.e. not only do you have multiple copies of the control element, you get multiple copies of the array it's dependent on as well). E.g:
<MenuItem x:Key="menuItem1" x:Shared="False"
Header="Shared menu item">
<MenuItem.ItemsSource>
<x:Array Type="{x:Type s:String}">
<s:String>value #1</s:String>
<s:String>value #2</s:String>
<s:String>value #3</s:String>
</x:Array>
</MenuItem.ItemsSource>
</MenuItem>
- 在代码隐藏中定义数组(例如,作为 C#
static readonly
字段而不是 XAML).例如:
- Defining the array in code-behind (e.g. as a C#
static readonly
field instead of in XAML). E.g.:
public static readonly string[] MenuItemValues = { "value #1", "value #2", "value #3" };
然后例如:
<MenuItem x:Key="menuItem1" x:Shared="False"
ItemsSource="{x:Static App.MenuItemValues}"
Header="Shared menu item"/>
- 使用不同的标记声明集合.例如.使用
ArrayList
或继承List
的非泛型类(因为 XAML 和泛型不能很好地配合使用).
- Declaring the collection using different markup. E.g. use
ArrayList
or a non-generic class that inheritsList<T>
(since XAML and generics don't play nicely together).
XAML 对我来说看起来不错.我做错了什么吗?我是否违反了 XAML 编译器和/或 WPF 强加的一些我不知道的按设计"规则?
The XAML looks fine to me. Have I done something wrong? Did I violate some "by design" rule the XAML compiler and/or WPF imposes and which I'm not aware of?
这不是我第一次遇到 x:Array
标记扩展导致问题的问题(请参阅 XAML 无法编译,但没有任何错误消息,如果用户定义的对象是第一个资源,紧随其后的是 x:Array 资源 和 在 Visual Studio 中声明 x:Array of x:Reference 元素时出现虚假 XAML 错误),但我想检查以确保我没有忽略此处的某些内容,并且我编写的 XAML 实际上应该作为我期待.
This isn't the first time I've run into problems with the x:Array
markup extension causing problems (see XAML fails to compile, but without any error message, if user-defined object is first resource and followed immediately by x:Array resource and Spurious XAML errors in Visual Studio when declaring x:Array of x:Reference elements), but I want to check to make sure I'm not overlooking something here and that the XAML I wrote should in fact work as I expect.
附录:
目前,由于缺乏解释我错误地编写 XAML 的答案,我将假设我认为这是 XAML 编译器和/或 WPF 中的错误是正确的.我已在 Microsoft Connect 站点上提交了错误报告,以防其他人遇到此问题并希望加入:
For now, lacking an answer explaining that I've written the XAML incorrectly, I'm going to assume that I'm correct in my belief that this is a bug in the XAML compiler and/or WPF. I have submitted a bug report on the Microsoft Connect site, in case anyone else runs into this and would like to chime in:
推荐答案
将
显式写入
:
<Window x:Class="TestxSharedMenuItem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary> <!-- modified here -->
<x:Array x:Key="menuItemValues1" Type="{x:Type s:String}">
<s:String>value #1</s:String>
<s:String>value #2</s:String>
<s:String>value #3</s:String>
</x:Array>
<MenuItem x:Key="menuItem1" x:Shared="False"
ItemsSource="{StaticResource menuItemValues1}"
Header="Shared menu item"/>
</ResourceDictionary> <!-- modified here -->
</Window.Resources>
<StackPanel>
<Menu HorizontalAlignment="Left" VerticalAlignment="Top">
<StaticResource ResourceKey="menuItem1"/>
<StaticResource ResourceKey="menuItem1"/>
</Menu>
</StackPanel>
</Window>
我遇到了一个非常相似的问题(实际上,完全相同,只有 UserControl).当我尝试上述解决方法时,我很绝望:),但它奏效了.
我现在刚刚用您的示例代码尝试了它,使用显式 <ResourceDictionary>
它可以由我使用,没有它就不行.
I had a very similar issue (actually, quite exactly the same, only with UserControl). I was desperate when I tried the above workaround :), but it worked.
I've just tried it out with your example code now, with explicit <ResourceDictionary>
it works by me, without it it doesn't.
这篇关于为什么 x:Array 元素会导致其后的任何 x:Shared 属性被忽略?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!