作为选项卡内容控件的DataContext的主ViewModel包含大量属性。模型本身实现了一个继承INotifyPropertyChanged的抽象类。每个属性集都可以通过抽象类的方法运行。因此,他们都已完全注册了通知,并且大部分工作正常。
我有一个布尔属性绑定到内容控件上许多控件的IsEnabled
属性。这是因为用户在运行服务器查询时不应更改值。所有控件的绑定完全相同:
IsEnabled="{Binding Path=IsIndicative}"
几乎每个像这样的控件都是RadComboBox
(Telerik)。只有 1 才能响应绑定。在屏幕截图中,"无"组合框被禁用,但所有其他组合都没有。它们是完全相同的类型,它们都使用相同的父DataContext属性。
我无法确定为什么其中一个人正在响应绑定,但其他人却忽略了它。您也可以看到日期下拉菜单,但这些日期下拉菜单会嵌套在一个视图中,我稍后会再次使用它。
我需要帮助确定IsEnabled
绑定的内容以及忽略它的原因。
附加说明:我甚至在VS2012中添加了代码隐藏作为解决方法,但现在甚至可能已经停止工作了!
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有一些差异,但布局和控制方向完全相同。
<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 -->
答案 0 :(得分:0)
其他人发布的答案指出我朝着正确的方向走了。所以,我正在创建这个答案,以防其他人遇到同样的问题。
关键问题是Command
属性及其相应的CanExecute
功能将覆盖IsEnabled
属性。在我们的例子中,CanExecute
方法总是返回true,因此控件不会禁用。集中式基本视图处理所有命令绑定,因此未编码以专门检查命令是否真的可以执行。还有一个中心ViewModel绑定到该视图,以便在整个窗口中使用。
要解决此问题,我必须执行以下操作:
List<string>
字段以包含应受各种值影响的控件名称。我可能会更改它来检查命令本身(类似于我们的Executed
处理程序的工作方式),但这可以完成工作。CanExecute
处理程序以检索源控件的名称,然后返回适当的值。IsEnabled
绑定。控件名称在初始化时填充,如下所示:
controlsSell = new List<string>();
controlsSell.AddRange(new string[] {
"sellButton",
"OptionsSellButton"
});
controlsBuy = new List<string>();
controlsBuy.AddRange(new string[] {
"buyButton",
"OptionsBuyButton"
});
最终的CanExecute
处理程序最终看起来像这样。
/// <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;
}
}
}
}
}
通过此实现,所有控件都会根据值正确更改IsEnabled
状态。