Определения команд WPF, определенные в одном окне, недоступны в другом - PullRequest
2 голосов
/ 25 октября 2011

У меня есть проблемы, когда у меня есть все эти CommandBindings, определенные в MainWindow, и указанные команды доступны в этом окне для использования в любом Button или MenuItem.Проблема в том, что если в других окнах привязка команды недоступна (она всегда ложна), даже если владельцем нового окна является MainWindow.

Вы можете увидеть проблему здесь.

Любая помощь действительно приветствуется.

Вот код.

Главное окно XAML:

<Window x:Class="ContextMenuDialogProblem.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ContextMenuDialogProblem"
        Title="MainWindow" Height="350" Width="525"
        FocusManager.FocusedElement="{Binding RelativeSource={x:Static RelativeSource.Self}, Mode=OneTime}">
    <Window.CommandBindings>
        <CommandBinding Command="local:LocalCommandManager.ShowDialogCommand" CanExecute="CanExecuteShowDialogCommand" Executed="ShowDialogCommandExecuted" />
    </Window.CommandBindings>
    <Window.ContextMenu>
        <ContextMenu>
            <MenuItem Command="local:LocalCommandManager.ShowDialogCommand" />
        </ContextMenu>
    </Window.ContextMenu>
    <Grid Background="Red">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Button Grid.Row="0"
                Content="Open SubWindow"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Padding="6"
                Click="Button_Click" />
        <Button Grid.Row="1"
                Content="Show Dialog Command Test"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Padding="6"
                Command="local:LocalCommandManager.ShowDialogCommand" />
    </Grid>
</Window>

Главное окно CS:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void CanExecuteShowDialogCommand(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;
    }

    private void ShowDialogCommandExecuted(object sender, ExecutedRoutedEventArgs e)
    {
        MessageBox.Show("Show Dialog");   
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Window wnd = new SubWindow() { Owner = this };
        wnd.Show();
    }
}

CS LocalCommandManager:

public static class LocalCommandManager
{
    private static object syncRoot = new object();

    private static RoutedUICommand _showDialogCommand;
    public static RoutedUICommand ShowDialogCommand
    {
        get
        {
            lock (syncRoot)
            {
                if (_showDialogCommand == null)
                    _showDialogCommand = new RoutedUICommand("Show Dialog", "ShowDialogCommand", typeof(LocalCommandManager));
                return _showDialogCommand;
            }
        }
    }
}

Подокно XAML:

<Window x:Class="ContextMenuDialogProblem.SubWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:local="clr-namespace:ContextMenuDialogProblem"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="SubWindow" Height="300" Width="300">
    <Grid>
        <Button Command="local:LocalCommandManager.ShowDialogCommand" Content="Show Dialog" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="6" />
    </Grid>
</Window>

Ответы [ 3 ]

3 голосов
/ 25 октября 2011

Область действия CommandBindings ограничена элементом, в котором она определена, поэтому это поведение совершенно нормально.Вы должны добавить CommandBinding к SubWindow, если хотите использовать его там.

1 голос
/ 03 июля 2013
<StackPanel Background="Transparent">
    <StackPanel.ContextMenu>
        <ContextMenu ItemsSource="{Binding Path=AnotherWindow.CommandBindings}">
            <ContextMenu.ItemContainerStyle>
                <Style TargetType="{x:Type MenuItem}">
                    <Setter Property="Header" Value="{Binding Path=Command.Name}" />
                    <Setter Property="Command">
                        <Setter.Value>
                            <MultiBinding Converter="{StaticResource commandConverter}">
                                <Binding />
                                <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ContextMenu}}" />
                            </MultiBinding>


public class CommandConverter : IMultiValueConverter
{
    public object Convert(object[] value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var cb = value[0] as CommandBinding;
        var cm = value[1] as ContextMenu;

        if(cb == null || cm == null)
            return null;

        cm.CommandBindings.Add(cb);
        return cb.Command;
    }

    public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

отлично работает на .net 4.0

0 голосов
/ 26 августа 2018

Если вы хотите добавить команду для всех окон, это решение:

    public partial class App : Application
    {
        public App()
        {
            var binding = new CommandBinding(MyCommands.DoSomethingCommand, DoSomething, CanDoSomething);

            // Register CommandBinding for all windows.
            CommandManager.RegisterClassCommandBinding(typeof(Window), binding);
        }

        private void DoSomething(object sender, ExecutedRoutedEventArgs e)
        {
            ...
        }

        private void CanDoSomething(object sender, CanExecuteRoutedEventArgs e)
        {
            ...
            e.CanExecute = true;
        }
    }
...