绑定自定义附加属性和OnSetPropertyCallback

时间:2010-07-17 13:11:07

标签: wpf binding

一个窗口有一个绑定到集合的MenuItem,MenuItem有ItemTemplate,它包含另一个带有附加属性的MenuItem:

<Menu Background="Transparent">
        <MenuItem ItemsSource="{Binding SomeThings}" Header="Menu">
            <MenuItem.ItemTemplate>
                <DataTemplate>
                    <MenuItem Header="{Binding MenuTitle}" WpfApplication30:MainWindow.KeyGesture="{Binding KeyGesture}"/>
                </DataTemplate>
            </MenuItem.ItemTemplate>
        </MenuItem>
    </Menu>

数据源和附加属性的声明:

private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        DataContext = new { 
            SomeThings = new[]
                {
                    new { MenuTitle = "Title 1", KeyGesture = new KeyGesture(Key.A, ModifierKeys.Control) }, 
                    new { MenuTitle = "Title 2", KeyGesture = new KeyGesture(Key.B, ModifierKeys.Control) }, 
                    new { MenuTitle = "Title 3", KeyGesture = new KeyGesture(Key.C, ModifierKeys.Control) }, 
                } };
    }

    public static string GetKeyGesture(MenuItem obj)
    {
        return (string)obj.GetValue(KeyGestureProperty);
    }

    public static void SetKeyGesture(MenuItem obj, string value)
    {
        obj.SetValue(KeyGestureProperty, value);
    }

    public static readonly DependencyProperty KeyGestureProperty =
        DependencyProperty.RegisterAttached("KeyGesture", typeof(KeyGesture), typeof(MainWindow), 
            new PropertyMetadata(OnSetKeyGestureCallback));

    private static void OnSetKeyGestureCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        var window = GetWindow(dependencyObject);
        var keyGesture = (KeyGesture)e.NewValue;
        window.KeyDown += (sender, keyArgs) =>
        {
            if (keyArgs.Key == keyGesture.Key && keyArgs.KeyboardDevice.Modifiers == keyGesture.Modifiers)
            {
                window.Background = Brushes.AntiqueWhite;
            }
        };

    }

调用OnSetKeyGestureCallback后,用户可以使用快捷方式执行操作。但只有在打开菜单后才会调用OnSetKeyGestureCallback。因此,在用户打开菜单之前,快捷方式不可用。如何在窗口或菜单加载后立即调用OnSetKeyGestureCallback?

2 个答案:

答案 0 :(得分:0)

DataTemplate MenuItem的{​​{1}}包含MenuItem。因此,您的视觉树中将有两个MenuItem,一个是另一个的孩子。子项将正确设置属性,但父项不会。

如果您需要在MenuItem上指定一个属性,则应使用ItemContainerStyle

<MenuItem ItemsSource="{Binding SomeThings}" Header="Menu">
    <MenuItem.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="Header" Value="{Binding MenuTitle}"/>
            <Setter Property="MainWindow.KeyGesture" Value="{Binding KeyGesture}"/>
        </Style>
    </MenuItem>
</MenuItem>

至于为什么你的连接在Menu打开之前没有运行,这是因为Menu的子项是虚拟化的,直到必要时才创建(即直到父Menu打开了)。您也可以覆盖用于托管子项的Panel

<MenuItem>
    <MenuItem.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="Header" Value="{Binding MenuTitle}"/>
            <Setter Property="MainWindow.KeyGesture" Value="{Binding KeyGesture}"/>
        </Style>
    </MenuItem>
    <MenuItem.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel/>
        </ItemsPanelTemplate>
    </MenuItem.ItemsPanel>
</MenuItem>

答案 1 :(得分:0)

不需要解决此问题的方法。为快捷方式做了不同的实现。