c# - 使用命令按钮的异常禁用行为

标签 c# wpf xaml mvvm

我很抱歉这么罗嗦,但我想让情况完全清楚。如果您是 WPF 专业人士,请看一下。

有两个CollectionViewSource绑定(bind)到ItemsControls使用 UserControl要显示的 View StackPanels或定制Buttons .下面的屏幕截图中显示的每一侧都有一个。我遇到的问题是,当设置父集合属性时,DataTemplate 中的所有按钮 View 被禁用。即使是上面的 2 个按钮也有同样的问题,即使它们在我最近的编辑之前工作。

如果我单击表单或按任意键,按钮将启用。一旦属性重置为新编辑和排序的集合,它们就会再次禁用。冲洗并重复。这就是它的样子。第一帧是它的启动方式(灰色使用 StackPanel ),第二帧是单击 RFS 按钮时的样子,第三帧是当我单击任意位置或按下某个键时发生的情况。

Disable-Enable behavior

我一直在兜圈子尝试一些事情。唯一似乎有效的是代码隐藏的解决方法,它将焦点集中在一件事上,然后再返回。但是,如果用户尝试使用其他仪表板项目之一,这对用户不利。

由于所有这些的 WPF 非常庞大,因此我将尝试仅包含相关部分。这些是 ItemsControls在 TabItemControl ( UserControl ) 上。

        <!-- BID (SELL) DEPTH -->
        <ItemsControl Grid.Row="0" Grid.Column="0" x:Name="bidDepthList" ItemsSource="{Binding Source={StaticResource BidDepthCollection}}"
                      Visibility="{Binding Path=IsMultilegEnabled, Converter={StaticResource CollapsedConverter}}">
           <ItemsControl.ItemTemplate>
              <DataTemplate DataType="{x:Type viewmodels:DepthLevelViewModel}">
                 <v:DepthLevelRowView x:Name="BidDepthLevelRowViewControl" DataContext="{Binding}" HorizontalAlignment="Center" Margin="1,0,1,3" />
              </DataTemplate>
           </ItemsControl.ItemTemplate>
        </ItemsControl>

        <!-- ASK (BUY) DEPTH -->
        <ItemsControl Grid.Row="0" Grid.Column="1" x:Name="askDepthList" ItemsSource="{Binding Source={StaticResource AskDepthCollection}}"
                      Visibility="{Binding Path=IsMultilegEnabled, Converter={StaticResource CollapsedConverter}}">
           <ItemsControl.ItemTemplate>
              <DataTemplate DataType="{x:Type viewmodels:DepthLevelViewModel}">
                 <v:DepthLevelRowView x:Name="AskDepthLevelRowViewControl" DataContext="{Binding}" HorizontalAlignment="Center" Margin="1,0,1,3" />
              </DataTemplate>
           </ItemsControl.ItemTemplate>
        </ItemsControl>

正在使用的 View 在网格内有 4 个“控件”。根据状态(RFS OFF/RFS ON)和它们在哪一侧(Sell/Buy),一次只显示一个。其他人都崩溃了。如您所见,这很好。

他们之间唯一的共同点是他们有自己的Command。设置,顶部的大多数控件都正确禁用/启用。如果采取任何鼠标或键盘操作,按钮正确启用的事实告诉我 CanExecute处理程序正在工作,但不是立即。其他控件在我制作 后开始工作these changes ,但随后大按钮开始表现不佳,就像深度按钮一直在做的那样。

我试过使用 CommandManager.InvalidateRequerySuggested();更改收藏后,但这并没有帮助。

注意:即使像这样简单的事情也会发生这种情况:
<Button x:Name="TestBuyButton" Command="{x:Static ptcommands:OrderCommands.Buy}" CommandTarget="{Binding RelativeSource={RelativeSource Self}}" Content="Test Buy" />

我知道 bool 值设置正确,因为我添加了测试 CheckBoxes 以使用 IsChecked 显示当前值。而且,一旦采取任何输入操作,它们都会启用,包括非常基本的按钮。

还有什么我遗漏的东西或我可以采取的不同方法吗?

编辑:我最终使用了 Dispatcher从事件线程调用我的显示更新例程到 UI 线程。 bool 值已设置,但 WPF 仍然没有重新查询 Command .但是.. CommandManager.InvalidateRequerySuggested()打电话然后工作!我唯一不喜欢的是它听起来像是广播失效。我不希望重新查询所有命令。我只想重新查询 Buy 和 Sell 命令。我已经尝试了各种奇怪的方法来让那些工作,但到目前为止除了全局之外没有任何工作。

编辑 2:看起来好像 InvalidateRequerySuggested是要走的路。

来自 MSDN CommandManager.InvalidateRequerySuggested :

The CommandManager only pays attention to certain conditions in determining when the command target has changed, such as change in keyboard focus. In situations where the CommandManager does not sufficiently determine a change in conditions that cause a command to not be able to execute, InvalidateRequerySuggested can be called to force the CommandManager to raise the RequerySuggested event.



这可以解释为什么焦点改变和按键会导致按钮启用。该页面还显示将调用置于计时器中。因此,我认为它不像我想象的那样占用资源。所以,我想这是我的永久解决方案。

最佳答案

我必须进行一些更改才能在不更改焦点的情况下启用按钮。

bool 值是在从事件线程调用的方法中设置的。我曾尝试调用 CommandManager.InvalidateRequerySuggested伴随着它,但什么也没发生。最后我认为这可能与线程有关。这就是最终解决它的原因。

在选项卡管理器类(包含事件处理程序和其他逻辑)可以访问的父表单中,我添加了一个调用方法:

  Public Sub InvokeOnUiThread(ByRef uiAction As Action, Optional ByRef doAsync As Boolean = False)

     Dim dispatchObject As Dispatcher = orderTicketView.Dispatcher

     If (dispatchObject Is Nothing OrElse dispatchObject.CheckAccess()) Then
        uiAction()
     Else
        If doAsync Then
           dispatchObject.BeginInvoke(uiAction, DispatcherPriority.Normal)
        Else
           dispatchObject.Invoke(uiAction, DispatcherPriority.Normal)
        End If
     End If

  End Sub

在选项卡管理器事件处理程序中,我将其更改为通过调用程序调用更新例程:
formOrderTicketView.InvokeOnUiThread(New Action(AddressOf UpdateButtons))

UpdateButtons 的底部方法,我添加了对 CommandManager 的调用如果进行了需要重新查询的更改:
CommandManager.InvalidateRequerySuggested()

我不知道这会产生什么样的性能影响,但显然 WPF 在焦点变化等时以自己的方式执行它。直接调用它是强制它的建议方法。

来自 MSDN CommandManager.InvalidateRequerySuggested :

The CommandManager only pays attention to certain conditions in determining when the command target has changed, such as change in keyboard focus. In situations where the CommandManager does not sufficiently determine a change in conditions that cause a command to not be able to execute, InvalidateRequerySuggested can be called to force the CommandManager to raise the RequerySuggested event.



由于它现在正在工作,因此我将此作为解决方案。

关于c# - 使用命令按钮的异常禁用行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36295685/

相关文章:

xaml - 如何在 uwp 应用程序上正确启用 dpi 缩放

c# - ViewModel 中的文本框事件处理

c# - DataTable不适合这种线程操作吗?

c# - 如何使用 EPPlus 从 Excel 文件 (xlsx) 中获取/读取图片

c# - 如何在无状态(.NET 状态机库)中记录状态转换

c# - WPF:向窗口添加用户控件

c# - 如果声明是接口(interface),编译器无法识别泛型中的属性

wpf - 多对多(学生、类(class)示例)Datagrid xaml 绑定(bind)

c# - 使用匿名方法调用 WPF Dispatcher

c# - WPF Expander 在用户交互后忽略数据绑定(bind)