在我的 WPF 应用程序中有一个包含项目的列表框。列表框通过 XAML 中的 xmldataprovider 填充,然后将其绑定到列表框的 Itemssource 属性。
好吧,从 XAML,我通过执行以下操作将命令绑定到列表框:
<ListBox.CommandBindings>
<CommandBinding
Command="{x:Static local:mainApp.MyCmd}"
CanExecute="CanExecute"
Executed ="Executed" />
</ListBox.CommandBindings>
但我不知道如何以编程方式将命令绑定到每个列表框项。怎么做?
提前致谢。
首先很抱歉,没有将其作为评论发布。我不能把这一切都放在评论中。
好的,是的,我没有使用 ICommandSource 的 Executed 和 CanExecute 属性,尽管我已经在自定义类中注册并实现了它们(在 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 获得正确的值,取决于后台工作人员是否完成,并且当 CanExecute 更改其值时引发自定义控件中的 CanExecuteChanged . 当后台工作人员启动时,它会被禁用,但完成后它不会被启用。我已经调试过,当后台工作人员完成时,我可以看到 CanExecuteChanged 被执行并且 this.Enabled 正在获得正确的值(true),但由于某种原因,在 UI 中,尽管它获得了正确的值并且尽管在 RunWOrkerCompleted(在后台worker) 我强制使用 CommandManager.InvalidateRequerySuggested() 更新 UI。
我通过取消注释行解决了这个问题:
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 会自动启用控件,否则它们会显示为禁用),对吗?
谢谢。