Assuming that the model has two properties Name
and Desc
:
public class Model : INotifyPropertyChanged
{
string _desc;
public string Desc { get { return _desc; } set { _desc = value; RaisePropertyChanged("Desc"); } }
string _name;
public string Name { get { return _name; } set { _name = value; RaisePropertyChanged("Name"); } }
public event PropertyChangedEventHandler PropertyChanged;
internal void RaisePropertyChanged(string propname)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname));
}
}
The view model should get a list of these properties (Items
) and have a SelectedItem
which indicates the current selected property. Other things are usual properties of a view model:
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
Models = new ObservableCollection<Model>() { new Model() {Name = "aaaa", Desc = "desc1" }, new Model() { Name = "bbbbb", Desc="desc2" } };
Items = new ObservableCollection<PropertyInfo>(typeof(Model).GetProperties());
SelectedItem = Items[0];
}
ObservableCollection<PropertyInfo> _items;
public ObservableCollection<PropertyInfo> Items { get { return _items; } set { _items = value; RaisePropertyChanged("Items"); } }
PropertyInfo _selectedItem;
public PropertyInfo SelectedItem { get { return _selectedItem; } set {
_selectedItem = value; RaisePropertyChanged("SelectedItem");
} }
ObservableCollection<Model> _models;
public ObservableCollection<Model> Models { get { return _models; }set { _models = value; RaisePropertyChanged("Models"); } }
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string propname)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname));
}
}
The view needs an MultiBinding
to get the selected properties value:
<DataGrid DataContext="{Binding}" ItemsSource="{Binding Models}" AutoGenerateColumns="False">
<DataGrid.Resources>
<local:conv1 x:Key="conv1" />
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn>
<DataGridTextColumn.Binding>
<MultiBinding Converter="{StaticResource conv1}">
<Binding />
<Binding Path="DataContext.SelectedItem" RelativeSource="{RelativeSource AncestorType=DataGrid, Mode=FindAncestor}" />
</MultiBinding>
</DataGridTextColumn.Binding>
<DataGridTextColumn.Header>
<ComboBox DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType=DataGrid, Mode=FindAncestor}}"
ItemsSource="{Binding Items}" SelectedItem ="{Binding SelectedItem, Mode=TwoWay}"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
in which
public class conv1 : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
Model m = values[0] as Model;
PropertyInfo pi = values[1] as PropertyInfo;
if (m != null && pi != null)
{
return pi.GetValue(m);
}
return Binding.DoNothing;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
DataContext = new ViewModel();
}
}
which results in this:
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…