В моем приложении WPF есть список с элементами. Список заполняется через xmldataprovider из XAML, а затем связывается с свойством Itemssource списка.
Ну, из XAML я связываю команду со списком, выполняя:
<ListBox.CommandBindings>
<CommandBinding
Command="{x:Static local:mainApp.MyCmd}"
CanExecute="CanExecute"
Executed ="Executed" />
</ListBox.CommandBindings>
но я не знаю, как программно привязать команду к каждому элементу списка. Как это сделать?
Заранее спасибо.
Сначала извините, не разместив его в качестве комментария. Я не могу поместить все это в комментарии.
Хорошо, да, я не использую свойства Executed и CanExecute ICommandSource, несмотря на то, что я зарегистрировал и реализовал их в пользовательском классе (в xaml они тоже комментированы). Я указал их в routedCommand, но не в пользовательском классе, я сделал это в конструкторе окна, выполнив следующее:
Код WinMain:
public WinMain()
{
InitializeComponent();
// Command binding. If I don't do this Executed and CanExecute are not executed
CommandBindings.Add(new CommandBinding(rcmd,
CommandBinding_Executed, CommandBinding_CanExecute));
}
и затем я реализую эти методы в коде WinMain так же, как он:
// ExecutedRoutedEventHandler
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
// Do stuff
}
// CanExecuteRoutedEventHandler
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
// cBgWorkers is a class that check if a background worker is running
e.CanExecute = !cBgWorkers.isRunning;
//if (LayoutListBox != null) LayoutListBox.IsEnabled = !cBgWorkers.isRunning;
}
и в WinMain XAML я вызываю команду следующим образом:
<Classes:CommandListBox x:Name="LayoutListBox"
Command="{x:Static local:WinMain.rcmd}"
... >
<...>
</Classes:CommandListBox>
И в моем собственном классе CommandListBox у меня есть CanExecuteChanged, в котором вы можете видеть, я включил или отключил элемент управления в зависимости от того, закончен ли фоновый рабочий:
private void CanExecuteChanged(object sender, EventArgs e)
{
this.Enabled = !cBgWorkers.isRunning;
}
но в пользовательском классе я не реализовал обработчик событий, который вы говорите, OnSelected.
Без реализации все идет нормально, команда вызова настраиваемого элемента управления и метод CanExecute достигнуты, и CanExecute получает правильное значение, истина или ложь в зависимости от того, завершен ли рабочий фон, или нет, а CanExecuteChanged в настраиваемом элементе управления вызывается, когда CanExecute меняет свою стоимость. Когда фоновый рабочий запускается, он отключается, но по окончании он не включается. Я отладил, и когда фоновый работник завершает работу, я вижу, что CanExecuteChanged выполняется и this.Enabled получает правильное значение (true), но по какой-то причине в пользовательском интерфейсе элемент управления продолжает отключаться, несмотря на то, что он получает правильное значение и несмотря на RunWOrkerCompleted (в фоновом режиме работник) Я заставляю обновлять пользовательский интерфейс с помощью CommandManager.InvalidateRequerySuggested ().
Я решаю это с помощью комментария:
if (LayoutListBox! = Null) LayoutListBox.IsEnabled =! CBgWorkers.isRunning;
в методе CanExecute. Я не понимаю, что происходит.
Тогда если я делаю то, что вы говорите, это не обязательно делать:
CommandBindings.Add(new CommandBinding(rcmd,
CommandBinding_Executed, CommandBinding_CanExecute));
и реализации CommandBinding_Executed & CommandBinding_CanExecute. Я прав?
но если я уберу эти методы, где я могу установить this.enabled =! CBgWorkers.isRunning?
Я бы хотел, чтобы WPF автоматически устанавливал свойство isEnabled для своего пользовательского элемента управления. Как это сделать?
Заранее спасибо.
Я применяю вашу статью о прикрепленном поведении с некоторыми изменениями, чтобы адаптировать ее к моему ListBox. Это не работает хорошо или, возможно, я делаю что-то не так. Я хочу, чтобы члены ListBox (listBoxItems) могли быть выбраны, когда выполняется длинная задача (фоновый работник). Итак, один из методов статьи, которую я изменил, это:
static void OnListBoxItemSelected(object sender, RoutedEventArgs e)
{
// Only react to the Selected event raised by the ListBoxItem
// whose IsSelected property was modified. Ignore all ancestors
// who are merely reporting that a descendant's Selected fired.
if (!Object.ReferenceEquals(sender, e.OriginalSource))
return;
ListBoxItem item = e.OriginalSource as ListBoxItem;
if (item != null)
{
// (*) See comment under
item.IsEnabled = !cBgWorkers.isRunning;
if (!cBgWorkers.isRunning)
{
item.BringIntoView();
}
}
}
(*) cBgWorkers - это открытый статический класс, имеющий некоторые методы и свойства.
Одним из свойств является isRunning, которое указывает, что в данный момент не работают фоновые рабочие. Затем, если фоновые рабочие не запущены, элементы списка должны быть включены, в противном случае они должны быть отключены, поэтому, когда пользователь нажимает на один элемент списка, текущая страница не меняется на другой, потому что я отключил его раньше (к каждому элементу списка прикреплен один страница в моем основном приложении).
Когда работает один из фоновых рабочих (bw) или все, и я выбираю элемент списка, все в порядке: элемент списка отключен, потому что работает bw, и он не позволяет изменить текущую страницу на другую. Конечно, если я отключил элемент списка (или элементы списка), я не смогу выбрать его снова, потому что он отключен, и это моя проблема, потому что я хочу, чтобы, когда bw заканчивал элементы списка, которые были отключены во время работы bw, они снова включаются. К сожалению, с прикрепленным поведением, как я вижу, WPF не делает это автоматически, и команды имеют это преимущество (элементы управления обновляются автоматически WPF). Итак, как отключить / повторно включить элементы списка, когда bw запущен или нет соответственно?
Насколько я знаю и вижу, одним из преимуществ прикрепленного поведения является то, что я думаю, что оно более эффективно, потому что оно не вызывает действия постоянно (только когда производится действие, например, выбор). Команды постоянно (не часто) проверяют возможность выполнения действий, связанных с элементами управления (поэтому, если они могут быть выполнены, WPF автоматически включает элементы управления, в противном случае они выглядят отключенными), верно?
Спасибо.