我很抱歉这是如此罗嗦,但我想让情况完全清楚。如果您是WPF专业人士,请查看。
有两个CollectionViewSource
绑定到ItemsControls
使用UserControl
视图来显示StackPanels
或自定义Buttons
。下面的屏幕截图中显示了每一面。我遇到的问题是,当设置父集合属性时,DataTemplate
视图中的所有按钮都被禁用。即使在我最近的编辑之前它们工作,即使是更高的2个按钮也会遇到同样的问题。
如果我点击表格,或按任意键,按钮启用。只要该属性重置为新编辑和排序的集合,它们就会再次禁用。冲洗并重复。这就是它的样子。第一帧是它的开始方式(灰色使用StackPanel
),第二帧是单击RFS按钮时的样子,第三帧是当我点击任意位置或按键时发生的情况。
我一直在尝试一些事情。似乎唯一有用的是代码隐藏的解决方法,它将焦点集中在一件事情然后又集中。但是,如果用户试图使用其他仪表板项目,那对用户来说就不会有好处。
由于所有这些的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事件。
这可以解释为什么焦点更改和按键会导致按钮启用。该页面还显示将呼叫置于计时器中。因此,我认为它不像我想象的那样资源密集。所以,我想这是我的永久解决方案。
答案 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事件。
由于它现在正在运作,我将此作为决议。