我怀疑是一个XAML编译器和/或WPF错误,但我想确保我在这里做错了(除了信任XAML编译器和/或WPF,就是:))。
考虑以下XAML以获得将重现问题的最小WPF程序:
<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会抛出异常:
XamlParseException
:&#39;将值添加到&#39; System.Windows.Controls.ItemCollection&#39;抛出异常。&#39;行号&#39; 20&#39;和行位置&#39; 23&#39;。
InnerException
是:
InvalidOperationException
:元素已有逻辑父级。在将旧父级附加到新父级之前,必须将其与旧父级分离。
当然,这正是人们期望在多个地方尝试使用相同控件的情况。但是使用x:Shared="False"
属性应导致每次检索MenuItem
资源对象的新实例时都会返回,从而避免出现此问题。
出于某种原因,在x:Array
元素之前使用MenuItem
元素会导致x:Shared
属性被忽略,导致在资源中共享一个MenuItem
元素被引用,因此导致异常。
其他观察:
x:Shared
添加到x:Array
元素没有帮助(它不应该,但我认为值得检查)。MenuItem
元素是否实际引用x:Array
元素并不重要。仅存在x:Array
元素就足以导致问题。MenuItem
,因为这是我遇到问题的地方,但问题也出现在其他控件类型中。解决方法包括:
x:Array
移至其他ResourceDictionary
(例如App.xaml
)。它的存在似乎只影响它所找到的字典声明。 (这样做可能也可能不可行,具体取决于需要声明非共享控制资源的位置。)x:Array
以后出现在字典声明中,而不是非共享控制资源的声明。当然,如果非共享控制资源需要x:Array
元素,那么这无济于事。x:Array
与非共享控件内联,而不是作为单独的资源。这解决了前两种解决方案中可能存在的依赖性问题,但当然会阻止x:Array
与可能使用它的其他字典条目共享,并加剧围绕非可共享控制元素的问题(即你不仅拥有控制元素的多个副本,而且还获得了它所依赖的数组的多个副本。 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>
static readonly
字段而不是在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<T>
的非泛型类(因为XAML和泛型不能很好地协同工作)。
XAML对我来说很好看。我做错了什么吗?我是否违反了一些&#34;设计&#34;规则XAML编译器和/或WPF强加什么,我不知道?
这是我第一次遇到导致问题的x:Array
标记扩展问题(请参阅XAML fails to compile, but without any error message, if user-defined object is first resource and followed immediately by x:Array resource和Spurious XAML errors in Visual Studio when declaring x:Array of x:Reference elements),但我想要检查以确保我不会忽略这里的某些内容,而且我写的XAML实际上应该像我期望的那样工作。
的附录:
目前,由于缺乏解释我已经错误地写了XAML的答案,我将假设我认为这是XAML编译器中的错误并且/我是正确的。或WPF。我已经在Microsoft Connect站点上提交了一个错误报告,以防其他人遇到此问题并希望加入:
答案 0 :(得分:1)
将<ResourceDictionary>
明确地写入<Window.Resources>
:
<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>
它由我工作,没有它它没有。