#c# #wpf #commandbinding
#c# #wpf #привязка команд
Вопрос:
У меня возникают проблемы, когда у меня есть все эти привязки команд, определенные в главном окне, и указанные команды доступны в этом окне для использования в любой кнопке или элементе меню. Проблема в том, что если в других окнах привязка команд недоступна (это всегда false), даже если владельцем нового окна является 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 MainWindow:
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>
Ответ №1:
Область действия CommandBindings
ограничена элементом, в котором она определена, поэтому такое поведение совершенно нормально. Вы должны добавить CommandBinding
to SubWindow
, если хотите использовать его там.
Комментарии:
1. Хммм, я боялся, что это проблема… знаете ли вы какой-либо обходной путь для этого?
2. Объявление привязки команд в подокне является обходным решением 😉
3. Или вы можете программно добавить привязку команд из главного окна в дочернее окно перед вызовом Show
4. ха-ха, нет, это сложное решение = (, хорошо, я попробую, проблема в том, что привязки команд довольно сложные (хотя и не слишком), спасибо!
5. Мне больше нравится второй =). Я попробую оба варианта. Спасибо!
Ответ №2:
<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
Ответ №3:
Если вы хотите добавить команду для всех окон, это решение:
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;
}
}