首先是一些背景知识,可以浓缩为编辑VatCodeViewModel的一个属性VatCode。
我在 ViewModel 中有一个具有两个特定属性的 StockItem:
public class StockItemViewModel : ViewModelBase
{
private VatCodeViewModel _vatCode;
public VatCodeViewModel VatCode
{
get { return _vatCode; }
set
{
if (_vatCode != value)
{
_vatCode = value;
RaisePropertyChanged("VatCode");
}
}
}
}
VatCode 属性接受一个 VatCodeViewModel 类型。
为了管理编辑体验,我有一个名为 EditStockItemViewModel 的 ViewModel。这具有元数据,例如 IsDirty、IsNew 等,但将 Item 属性设置为正在编辑的项目 - 在本例中是 StockItemViewModel 的实例。Item 属性位于(TViewModel == StockItemViewModel 的)基类中...
public class UnMappedEditableViewModelBase<TViewModel> : ViewModelBase
{
private TViewModel _item;
public TViewModel Item
{
get { return _item; }
set
{
if (_item != value)
{
_item = value;
RaisePropertyChanged("Item");
}
}
}
}
和实现类(EditStockItemViewModel,它有StockItemViewModel的Item)......
public class EditStockItemViewModel : UnMappedEditableViewModelBase<StockItemViewModel>
{
private ObservableCollection<VatCodeViewModel> _vatCodes=new ObservableCollection<VatCodeViewModel>();
public ObservableCollection<VatCodeViewModel> VatCodes
{
get { return _vatCodes; }
set
{
if (_vatCodes != value)
{
_vatCodes = value;
RaisePropertyChanged("VatCodes");
}
}
}
public EditStockItemViewModel()
:base()
{
if (IsInDesignMode)
{
}
else
{
RefreshVatCodesList(null); // refreshes VatCodes property
Save = new RelayCommand(() =>
{
// save functionality snipped
}, () =>
{
bool canExecute = Item.VatCode!=null; // this is ALWAYS null - binding failing
return canExecute;
});
}
}
}
因此 ViewModel.Item 属性始终是正在编辑的项目。
我观点的一个片段......
<TextBlock Text="VAT Code:" Grid.Column="1" Grid.Row="3" Style="{StaticResource ComboHeaderTextBlock}" />
<telerik:RadComboBox Grid.Column="2" Grid.Row="3" Style="{StaticResource RadComboBox}" Width="300" HorizontalAlignment="Left"
ItemsSource="{Binding VatCodes}" SelectedValuePath="Item.VatCode"
ClearSelectionButtonVisibility="Collapsed"
CanAutocompleteSelectItems="True"
CanKeyboardNavigationSelectItems="True"
IsEditable="False"
OpenDropDownOnFocus="False"
IsFilteringEnabled="False"
EmptyText="Select ...">
<telerik:RadComboBox.SelectedValue>
<Binding Path="Item.VatCode" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay" RelativeSource="{RelativeSource FindAncestor,AncestorType={x:Type UserControl}}" >
<Binding.ValidationRules>
<DataErrorValidationRule />
</Binding.ValidationRules>
</Binding>
</telerik:RadComboBox.SelectedValue>
<telerik:RadComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Key}" Style="{StaticResource TextBlock}" />
<TextBlock Text="{Binding Name}" Style="{StaticResource DimTextBlock}" />
<TextBlock Text="{Binding ActiveRate.Rate}" Margin="5 5 0 5" />
<TextBlock Text="%" Margin="0 5 5 5" />
</StackPanel>
</DataTemplate>
</telerik:RadComboBox.ItemTemplate>
</telerik:RadComboBox>
所以在这一切结束时,我有:
绑定到 [ViewModel].Item.VatCode 并使用 [ViewModel].VatCodes 作为源的增值税代码。
该列表已填充并且看起来很好。我知道 ViewModel 绑定正确。
问题是增值税代码没有绑定到 Item.VatCode 属性。因此,当我使用 Save 方法时,Item.VatCode 属性为空(即不工作)。
我收到以下似乎相关的绑定错误:
System.Windows.Data 错误:17:无法从“”(类型“VatCodeViewModel”)获取“项目”值(类型“字符串”)。BindingExpression:Path=Item.VatCode; DataItem='VatCodeViewModel' (HashCode=27875274); 目标元素是 'RadComboBox' (Name=''); 目标属性是“NoTarget”(类型“对象”) TargetParameterCountException:“System.Reflection.TargetParameterCountException:参数计数不匹配。
显然,该错误表明我的绑定表达式 Item.VatCode 是可疑的,但我不确定如何更正它。