使用命令按钮

时间:2016-03-29 21:46:15

标签: c# wpf xaml mvvm

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

有两个CollectionViewSource绑定到ItemsControls使用UserControl视图来显示StackPanels或自定义Buttons。下面的屏幕截图中显示了每一面。我遇到的问题是,当设置父集合属性时,DataTemplate视图中的所有按钮都被禁用。即使在我最近的编辑之前它们工作,即使是更高的2个按钮也会遇到同样的问题。

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

Disable-Enable behavior

我一直在尝试一些事情。似乎唯一有用的是代码隐藏的解决方法,它将焦点集中在一件事情然后又集中。但是,如果用户试图使用其他仪表板项目,那对用户来说就不会有好处。

由于所有这些的WPF非常庞大,我将尝试仅包括相关部分。这些是TabItemControl(ItemsControls)上的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>

正在使用的视图有4个&#34;控件&#34;在网格内部。根据状态(RFS OFF / RFS ON)以及它们在哪一侧(销售/购买),一次只显示其中一个。其他人都崩溃了。如你所见,这很好。

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

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

注意:即使是这样简单的事情,也会发生这种情况:

<Button x:Name="TestBuyButton" Command="{x:Static ptcommands:OrderCommands.Buy}" CommandTarget="{Binding RelativeSource={RelativeSource Self}}" Content="Test Buy" />

我知道布尔值设置正确,因为我添加了测试CheckBoxes以显示IsChecked的当前值。并且,只要采取任何输入操作,它们都会启用,包括极其基本的按钮。

我还缺少其他的东西,或者我可以采取不同的方法吗?

编辑:我最终使用Dispatcher从事件线程调用我的显示更新例程到UI线程。布尔值得到设置,但WPF仍然没有重新查询Command。但是CommandManager.InvalidateRequerySuggested()电话随后工作了!我唯一不喜欢的就是广播失效。我不希望重新获得所有命令。我只想要买入和卖出命令来重新查询。我尝试过各种奇怪的尝试,只是为了让那些工作起作用,但到目前为止,除了全球之外,什么都没有效果。

编辑2:好像InvalidateRequerySuggested就好了。

来自MSDN CommandManager.InvalidateRequerySuggested

  

CommandManager仅关注确定命令目标何时更改的某些条件,例如键盘焦点的更改。在CommandManager无法充分确定导致命令无法执行的条件更改的情况下,可以调用InvalidateRequerySuggested以强制CommandManager引发RequerySuggested事件。

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

2 个答案:

答案 0 :(得分:0)

绑定到按钮的命令......是否有CanExecute委托?如果是这样,则必须在重新评估该委托时引发CanExecuteChanged。另外,请确保CanExecute的实现没有被破坏并错误地返回false;

答案 1 :(得分:0)

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

布尔值是在从事件线程调用的方法中设置的。我曾尝试过调用CommandManager.InvalidateRequerySuggested,但没有任何反应。最终我认为这可能与线程有关。这就是最终解决它的问题。

在tab管理器类(包含事件处理程序和其他逻辑)可以访问的父窗体中,我添加了一个invoke方法:

  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

  

CommandManager仅关注确定命令目标何时更改的某些条件,例如键盘焦点的更改。在CommandManager无法充分确定导致命令无法执行的条件更改的情况下,可以调用InvalidateRequerySuggested以强制CommandManager引发RequerySuggested事件。

由于它现在正在运作,我将此作为决议。