Привязка к RoutedUICommand, который не находится в codebehind
у меня есть статический класс, который содержит RoutedUICommand, который я хотел бы использовать в привязке.
public static class CommandLibrary
{
public static ProjectViewModel Project { get; set; }
public static RoutedUICommand AddPage { get; private set; }
static CommandLibrary()
{
AddPage = new RoutedUICommand("AddPage", "AddPage", typeof(CommandLibrary));
}
public static void AddPage_Executed(object sender, ExecutedRoutedEventArgs args)
{
Project.AddPage();
}
public static void AddPage_CanExecute(object sender, CanExecuteRoutedEventArgs args)
{
// We need a project before we can add pages.
if (Project != null)
{
args.CanExecute = true;
}
else
{
// Did not find project, turning Add Page off.
args.CanExecute = false;
}
}
}
когда я пытаюсь создать CommandBinding для этой команды AddPage, VS бросает истерику, жалуясь, что не может найти AddPage_CanExecute в Window1... Что не имеет смысла, учитывая, что все примеры, которые я видел, указывают, что этот XAML должен быть прекрасным, учитывая код, который у меня есть:
<Window x:Class="MyProject.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyProject">
<Menu>
<Menu.CommandBindings>
<CommandBinding Command="local:CommandLibrary.AddPage"
Executed="AddPage_Executed" CanExecute="AddPage_CanExecute" />
</Menu.CommandBindings>
<MenuItem Header="_Page">
<MenuItem Header="_New" Command="local:CommandLibrary.AddPage" />
</MenuItem>
</Menu>
</Window>
Я также пытался не включать Меню.Раздел CommandBindings и просто используя это (согласно этот вопрос что предполагает это, но не является конкретным):
<MenuItem Header="_New" Command="{x:Static local:CommandLibrary.AddPage}" />
это остановило поток ошибок, но пункт меню, который он генерирует, всегда отключен! CanExecute, чтобы никогда, кажется, не дозвонились. Я предполагаю, что привязка в этом случае также терпит неудачу, хотя и более тихо.
почему VS ненавидит мою команду и отказывается искать в нужном месте, чтобы найти выполненный и CanExecute методы? я видел несколько примеров (в Pro WPF Мэтью Макдональд и на нескольких пользовательских командных учебниках онлайн), которые сделали это, как я это делаю.
1 ответов
A CommandBinding
, как и любой другой элемент в визуальном дереве. Любые события, указанные на нем, будут обрабатываться корнем вашего визуального дерева (ваш Window
в данном случае). Это означает, что если вы переместите AddPage_Executed
и AddPage_CanExecute
для кода вашего окна позади, он будет работать. Это позволяет использовать одну и ту же команду во многих компонентах пользовательского интерфейса, но с разными обработчиками.
Я вижу, однако, что ваша команда выполняет некоторую логику против вашей модели представления. Чтобы сэкономить время и разочарование, поймите, что маршрутизируемые команды-неправильное решение здесь. Вместо этого инкапсулируйте свою команду в модель представления примерно так:
public class ProjectViewModel
{
private readonly ICollection<PageViewModel> _pages;
private readonly ICommand _addPageCommand;
public ProjectViewModel()
{
_pages = new ObservableCollection<PageViewModel>();
_addPageCommand = new DelegateCommand(AddPage);
}
public ICommand AddPageCommand
{
get { return _addPageCommand; }
}
private void AddPage(object state)
{
_pages.Add(new PageViewModel());
}
}
A DelegateCommand
реализация ICommand
который вызывает делегатов для выполнения и запроса команды. Это означает, что логика команды полностью завернута в команду, и вам не нужно CommandBinding
для предоставления обработчиков (вам не нужен CommandBinding
на всех). Таким образом, ваше представление просто привязывается к вашей виртуальной машине как следует:
<MenuItem Header="_New" Command="{Binding AddPageCommand}"/>
Я предлагаю вам прочитать эту серию постов, чтобы дать вам больше контекста: