在我的WPF应用程序中,我有很多视图模型,现在,需要"property-value"像网格。
我试图建立一个通用的目的视图模型,可以"注入";这样我就可以毫不费力地在新窗口中使用它们。为此,我编写了一个带有可观察集合的简单接口:
public interface IPropertyGridVM
{
ObservableCollection<(string Prop, object Val)> PropValueList
{
get;
set;
}
}
并且,在一个需要新的属性值网格的视图模型中:
public class ExistingVM : ViewModelBase<Model>, IPropertyGridVM
{
public ObservableCollection<(string Prop, object Val)> PropValueList
{
get;
set;
}
ExistingVM()
: base(new Model())
{
// "old" vm initialization
initPropValueList();
}
ExistingVM(Model model)
: base(model)
{
// "old" vm initialization
initPropValueList();
}
private void initPropValueList()
{
PropValueList = new ObservableCollection<(string Prop, object Val)>()
{
(nameof(Prop1), Prop1),
// ...
}
}
}
遵循应用程序的现有约定:
// This piece of code is inside a Dialog Manager
public void ShowPropertiesDialog<T>(T propValueLikeVm)
{
if (propValueLikeVm is IPropertyGridVM)
{
// create the dialog
PropertyGridDialog dialog = new PropertyGridDialog();
// assign the datacontext
dialog.DataContext = propValueLikeVm;
// till here is all ok, VM is correctly initialized and contains what I expected
dialog.ShowDialog();
}
}
现在,在我的常规XAML对话框中出现了麻烦:
<...
xmlns:vm="clr-namespace:ViewModels;assembly=ViewModels"
d:DataContext="{d:DesignData Type={x:Type vm:IPropertyGridVM},
IsDesignTimeCreatable=True}"
mc:Ignorable="d">
<!-- dialog styling and definition -->
<!-- Intellisense warns me of some problems in binding the PropValueList: "No DataContext value found for PropValueList"-->
<DataGrid ItemsSource="{Binding Path=PropValueList}">
<DataGrid.Columns>
<DataGridTextColumn Width="2*" Binding="{Binding Path=Prop}">
<!-- Text column styling -->
</DataGridTextColumn>
<DataGridTextColumn Width="2*" Binding="{Binding Path=Val}">
<!-- Text column styling -->
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
并且它是正确的:在运行时,我有绑定错误告诉我,属性Prop没有在类型为ValueTuple'2的对象中找到;属性Val没有在类型ValueTuple'2"的对象中找到,但我不知道为什么。
提示吗?
名称Prop
和Val
只有在编译之前才真正出现。它们实际上被命名为Item1
和Item2
。编译器会发挥一些魔力,让您在源代码中使用更好的名称。但是,这些是字段而不是属性,您可能需要在WPF中绑定属性。我建议你添加自己的类:
public class PropVal : INotifyPropertyChanged{
public string Prop {get;}
public object Val {get;}
public PropVal(string prop, object val) => (Prop, Val) = (prop, val);
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
我希望那会更可靠。如果您愿意,可以从相应的值元组添加隐式或显式转换。