为什么 x:Array 元素会导致其后的任何 x:Shared 属性被忽略? [英] Why does an x:Array element cause any x:Shared attribute following it to be ignored?

查看:16
本文介绍了为什么 x:Array 元素会导致其后的任何 x:Shared 属性被忽略?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我怀疑存在 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.

其他观察:

  1. x:Shared 添加到 x:Array 元素没有帮助(它不应该,但我认为值得检查).
  2. MenuItem 元素是否实际引用了 x:Array 元素并不重要.仅存在 x:Array 元素就足以导致问题.
  3. 上面的示例使用 MenuItem,因为这是我遇到问题的地方,但其他控件类型也会出现此问题.
  1. Adding x:Shared to the x:Array element doesn't help (it shouldn't, but I figured it was worth checking).
  2. It does not matter whether the MenuItem element is actually referencing the x:Array element or not. The mere presence of the x:Array element is sufficient to cause the problem.
  3. The example above uses MenuItem because this is where I ran across the problem, but the issue happens for other control types too.

变通方法包括:

  1. x:Array 移动到不同的 ResourceDictionary(例如在 App.xaml 中).它的存在似乎只影响找到它的字典声明.(这样做可能可行,也可能不可行,具体取决于需要声明非共享控制资源的位置).
  2. 移动 x:Array 在字典声明中出现在非共享控制资源声明的后面.当然,如果非共享控制资源需要 x:Array 元素,这也无济于事.
  3. 声明 x:Array 与非共享控件内联,而不是作为单独的资源.这解决了前两个变通方法中可能存在的依赖性问题,但当然会阻止 x:Array 与其他可能使用它的字典条目共享,并加剧了围绕非可共享的控制元素(即,您不仅拥有控制元素的多个副本,还获得它所依赖的数组的多个副本).例如:
  1. Moving the x:Array to a different ResourceDictionary (e.g. in App.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).
  2. 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 the x:Array element, this doesn't help.
  3. 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 the x: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>

  1. 在代码隐藏中定义数组(例如,作为 C# static readonly 字段而不是 XAML).例如:
  1. 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"/>

  1. 使用不同的标记声明集合.例如.使用 ArrayList 或继承 List 的非泛型类(因为 XAML 和泛型不能很好地配合使用).
  1. Declaring the collection using different markup. E.g. use ArrayList or a non-generic class that inherits List<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:

https://connect.microsoft.com/VisualStudio/feedback/details/2443920/declaring-x-array-element-in-resources-causes-x-shared-attribute-on-later-element-to-be-ignored

推荐答案

显式写入:

<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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆