我想提供一个上下文菜单,其中的项目在空间中有一个颜色样本,其中"图标"通常放置这些菜单项,即与MenuItem.Icon对应的空间。
但是颜色样本是动态的 - UserControl上的一个Brush属性(在这个精心设计的例子中)变为随机颜色以响应ContextMenuOpening事件 - 我尝试绑定它失败。
运行时,菜单项在图标空间中没有内容,Visual Studio的输出包含一个看起来不应该发生的错误。
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ContextMenu', AncestorLevel='1''. BindingExpression:Path=PlacementTarget.RandomBrush; DataItem=null; target element is 'Rectangle' (Name=''); target property is 'Fill' (type 'Brush')
这是控件的XAML:
<UserControl x:Class="ContextMenuItemIconTest.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.ContextMenu>
<ContextMenu>
<MenuItem Header="Do something">
<MenuItem.Icon>
<Rectangle Width="16" Height="16" Fill="{Binding PlacementTarget.RandomBrush, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</UserControl.ContextMenu>
<Grid>
</Grid>
背后的代码:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace ContextMenuItemIconTest
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
ContextMenuOpening += UserControl1_ContextMenuOpening;
}
void UserControl1_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
Random r = new Random();
RandomBrush = new SolidColorBrush(Color.FromRgb((byte)r.Next(256), (byte)r.Next(256), (byte)r.Next(256)));
}
#region RandomBrush (Dependency Property)
public Brush RandomBrush
{
get { return (Brush)GetValue(RandomBrushProperty); }
set { SetValue(RandomBrushProperty, value); }
}
public static readonly DependencyProperty RandomBrushProperty =
DependencyProperty.Register(
"RandomBrush",
typeof(Brush),
typeof(UserControl1),
new PropertyMetadata(new SolidColorBrush(Colors.Blue)));
#endregion
}
}
答案 0 :(得分:0)
不确定是否有更好的解决方案,但我认为这里的方案非常棘手。 Icon
内容似乎与视觉树完全分离。因此,您无法将绑定与RelativeSource
或ElementName
一起使用,奇怪的是,即使将Source
设置为某些{x:Reference}
也会导致某些循环引用错误。
我只是想到这个解决方案,有点hacky但它是可以接受的。有关Freezable
对象的有趣知识。其中的绑定(为某些属性设置)可以使用RelativeSource
以及ElementName
,即使它刚刚被声明为资源(添加到Resources
)。因此,在这种情况下,我们可以尝试使用从Freezable
派生的一些对象作为代理。由于此代理被声明为资源,因此我们可以将Binding
内Icon
设置为Source
,并将其设置为引用代理的某些StaticResource。然后它会工作。有许多来自Freezable
的对象供您选择,您甚至可以创建自己的类。但是我想用这里存在的东西。 DiscreteObjectKeyFrame
是最适合使用的对象。从技术上讲,它的Value
属性可以包含任何类型的对象。现在是工作代码:
<ContextMenu>
<ContextMenu.Resources>
<!-- the proxy here -->
<DiscreteObjectKeyFrame x:Key="o" KeyTime="0"
Value="{Binding PlacementTarget.RandomBrush,
RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
</ContextMenu.Resources>
<MenuItem Header="Do something">
<MenuItem.Icon>
<Rectangle Width="16" Height="16"
Fill="{Binding Value, Source={StaticResource o}}" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>