为什么多个IsEnabled绑定无法工作? [英] Why would multiple IsEnabled bindings fail to work?

查看:59
本文介绍了为什么多个IsEnabled绑定无法工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为选项卡内容控件的DataContext的主ViewModel包含很多属性。该模型本身实现了一个继承INotifyPropertyChanged的抽象类。每个属性的设置和获取都将通过抽象类的方法来运行。因此,它们都已完全通过通知注册,并且大多数都可以正常工作。

The main ViewModel that is the DataContext for the tab content control contains A LOT of properties. The model itself implements an abstract class that inherits INotifyPropertyChanged. EVERY property set and get runs through the methods of the abstract class. So, they are all fully registered with notification, and most of them work fine.

我有一个布尔属性绑定到 IsEnabled 内容控件上许多控件的属性。这是因为用户在运行服务器查询时不应更改值。对于所有控件,绑定都完全相同:

I have a single boolean property bound to the IsEnabled property of many controls on the content control. This is because the user shouldn't change values while it is running server queries. The binding is exactly the same for all of the controls:

IsEnabled="{Binding Path=IsIndicative}"

几乎每个这样的控件绑定都是 RadComboBox (Telerik )。只有 1 响应绑定。在屏幕截图中,无组合框已禁用,但其他所有组合框均未禁用。它们是完全相同的类型,并且都使用相同的父DataContext属性。

Almost every single control bound like that is a RadComboBox (Telerik). Only 1 is responding to the binding. In the screenshot, the "None" combobox is disabled, but all of the others aren't. They are the exact same type, and they are all using the same parent DataContext's property.

我无法确定为什么其中一个响应绑定,而其他人却忽略了。您可以看到日期下拉列表也发生了这种情况,但这是嵌套在View中的,稍后我会介绍。

I cannot determine why one of them is responding to the binding, but the others are ignoring it. It's also happening with the date dropdown you can see, but that's nested in a View, and I'll get to it later.

我需要帮助来确定正在进行 IsEnabled 绑定以及为什么忽略它的原因。

I need help determining what is going on with the IsEnabled binding and why it is ignoring it.

附加说明:甚至在VS2012中添加了代码隐藏作为变通方法,但现在看来似乎已停止工作!

Additional Note: I had even added code-behind as a workaround in VS2012, but now even that appears to have quit working!

     StrategyTypeComboBox.IsEnabled = isEnabled;
     QuantityNumericUpDown.IsEnabled = isEnabled;
     datePicker.IsEnabled = isEnabled;
     OptionsOrderTypeComboBox.IsEnabled = isEnabled;
     ExpirationTypeComboBox.IsEnabled = isEnabled;
     DeltaHedgeTypeComboBox.IsEnabled = isEnabled;
     TopPriceTypeToggle.IsEnabled = isEnabled;
     PriceInTypeComboBox.IsEnabled = isEnabled;

XAML示例

所有控件都具有完全相同的设置。唯一真正的区别是它们在其中是 Grid.Row 。显然,TextBlock和RadComboBox具有一些区别,但是布局和控件方向完全相同。

All of the controls have this same exact setup. The only real difference is which Grid.Row they are in. Obviously the TextBlock and RadComboBox have some differences, but the layout and control orientation are exactly the same.

        <Grid Grid.Row="0" Margin="5,3,5,3">
           <Grid.ColumnDefinitions>
              <ColumnDefinition Width="Auto" /> <!-- strategy_type label -->
              <ColumnDefinition Width="*" /> <!-- dotted line -->
              <ColumnDefinition Width="Auto" SharedSizeGroup="TopLeftGridValues" /> <!-- StrategyTypeComboBox -->
           </Grid.ColumnDefinitions>
           <TextBlock Foreground="{Binding Path=MainLabelTextColor}" Style="{StaticResource LabelStyle}" Grid.Column="0" Margin="5,0,2,0"  Height="Auto">
              <TextBlock.Text>
                 <Binding Path="strategy_type" Source="{x:Static util:Strings.Instance}" />
              </TextBlock.Text>
           </TextBlock>
           <Line Grid.Column="1" Style="{StaticResource DottedLineStyle}" />
           <telerikInput:RadComboBox Grid.Column="2" Style="{StaticResource LabelStyle}" MinWidth="60" Margin="3,0,3,0" HorizontalAlignment="Stretch"
                                     x:Name="StrategyTypeComboBox"
                                     IsEnabled="{Binding Path=IsIndicative}"
                                     Command="{x:Static ptcommands:OrderCommands.StrategyChanged}"
                                     CommandTarget="{Binding RelativeSource={RelativeSource Self}}"
                                     ItemsSource="{Binding Path=StrategyTypesCollection}"
                                     DisplayMemberPath="display"
                                     SelectedValuePath="value"
                                     SelectedIndex="{Binding Path=StrategyTypeSelectedIndex}">
              <telerikInput:RadComboBox.ItemsPanel>
                 <ItemsPanelTemplate>
                    <VirtualizingStackPanel />
                 </ItemsPanelTemplate>
              </telerikInput:RadComboBox.ItemsPanel>

           </telerikInput:RadComboBox>
        </Grid> <!-- Row 0: Strategy -->


推荐答案

其他人发表的答案指出我在右边方向不见了。所以,我创建这个答案是为了防止其他人遇到相同的问题。

The answer someone else posted that pointed me in the right direction is gone. So, I'm creating this answer in case anyone else runs into the same problem.

关键问题是 Command 属性及其相应的 CanExecute 功能将覆盖 IsEnabled 属性。在我们的例子中, CanExecute 方法始终返回true,因此不会禁用该控件。集中式基本视图处理所有命令绑定,因此未进行编码来专门检查命令是否真的可以执行。还有一个绑定到该视图的中央ViewModel,可以在整个窗口中使用。

The key issue is the Command property and its corresponding CanExecute functionality will override the IsEnabled property. In our case, the CanExecute method was always returning true, so the control would not disable. A centralized base view handles all of the command bindings, so it was not coded to check specifically for if a command really could be executed or not. There's also a central ViewModel that is bound to that view for use across the entire window.

要解决此问题,我必须执行以下操作:

To resolve this issue, I had to do the following:


  • 在ViewModel上创建布尔属性,可以使用与绑定的特定于选项卡的值相同的值从选项卡管理器中设置该属性。

  • 添加一些 List< string> 字段以包含应该受各种值影响的控件名称。我可能会更改它以检查命令本身(类似于我们的 Executed 处理程序执行此操作的方式),但这可以完成工作。

  • 更改 CanExecute 处理程序以检索源控件的名称,然后返回适当的值。

  • 删除所有<$内容控件中的c $ c> IsEnabled 绑定。

  • Create boolean properties on the ViewModel that could be set from the tab manager using the same values as the tab-specific values being bound.
  • Add some List<string> fields to contain control names that should be affected by the various values. I will probably change this to examine the command itself (similar to how our Executed handler does it), but this gets the job done.
  • Change the CanExecute handler to retrieve the source control's name, and then return the appropriate value.
  • Remove all of the IsEnabled bindings from the content control.

控件名称在初始化时填充,例如

The control names are populated at initialization, like this:

     controlsSell = new List<string>();
     controlsSell.AddRange(new string[] {
                                          "sellButton",
                                          "OptionsSellButton"
                                        });

     controlsBuy = new List<string>();
     controlsBuy.AddRange(new string[] {
                                         "buyButton",
                                         "OptionsBuyButton"
                                       });

最后的 CanExecute 处理程序看起来像

The final CanExecute handler ended up looking like this.

  /// <summary>
  /// Determines if the command can be executed based on TicketViewModel properties.
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  public void CanExecuteCustomCommand(object sender,
      CanExecuteRoutedEventArgs e)
  {
     // NOTE: This may need more complex handling such as in ExecutedCustomCommand.
     //       Right now, it is dependent on specific control names, which is not optimal.

     // This is usually always PTTicketView, not the originating control.
     Control target = e.Source as Control;
     // This is the control that actually executes the command.
     Control orig = e.OriginalSource as Control;

     if (orig == null)
     {
        e.CanExecute = false;
     }
     else
     {
        string ctlName = orig.Name;

        if (dataContext == null)
        {
           e.CanExecute = true;
        }
        else
        {
           if (dataContext.SelectedTab != TicketViewModel.Tabs.MultiLeg)
           {
              e.CanExecute = true;
           }
           else
           {
              if (controlsBuy.Contains(ctlName))
              {
                 e.CanExecute = dataContext.IsCommandBuyEnabled;
              }
              else if (controlsSell.Contains(ctlName))
              {
                 e.CanExecute = dataContext.IsCommandSellEnabled;
              }
              else if (controlsOther.Contains(ctlName))
              {
                 e.CanExecute = dataContext.IsCommandOtherEnabled;
              }
              else if (controlsExpiries.Contains(ctlName))
              {
                 e.CanExecute = (dataContext.IsExpiriesEnabled && dataContext.IsIndicative);
              }
              else if (ctlName.Equals("DealableTypeToggle"))
              {
                 e.CanExecute = dataContext.IsRFSEnabled;
              }
              else
              {
                 e.CanExecute = true;
              }
           }
        }
     }
  }

通过此实现,控件的 all 会根据值正确更改 IsEnabled 状态。

With this implementation, all of the controls correctly change IsEnabled state based on the values.

这篇关于为什么多个IsEnabled绑定无法工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆