问题
This is my XAML code:
<ComboBox Grid.Row="0" Margin="5" ItemsSource="{Binding Path=Clvm.Categories}">
</ComboBox>
<GridSplitter Grid.Row="0" Height="3" />
<DataGrid Grid.Row="1" AutoGenerateColumns="False" ItemsSource="{Binding Alvm.Artists}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" IsReadOnly="True" Binding="{Binding Id}" />
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Email" Binding="{Binding Email}" />
<DataGridComboBoxColumn Header="Category" SelectedItemBinding="{Binding Category}"
ItemsSource="{Binding Path=Clvm.Categories}" />
</DataGrid.Columns>
</DataGrid>
The ComboBox above is just for testing - I want to see if I can display all my Categories and it works well.
The DataGrid below is the control I really want. I want that Categories ComboBox as a column of the DataGrid. But the way I do it in the snippet obviously doesn't work as the data bindings for the columns are relative to the DataGrid's ItemsSource and not to the old DataContext. How can I switch it back for that binding?
The Control class:
public partial class ArtistManagementControl : UserControl {
public ArtistManagementControl() {
InitializeComponent();
IDatabase db = new MYSQLDatabase("Server = localhost; Database = ufo; Uid = root;");
SharedServices.Init(db);
Alvm = new ArtistListViewModel(SharedServices.GetInstance().ArtistService, SharedServices.GetInstance().CategoryService);
Clvm = new CategoryListViewModel(SharedServices.GetInstance().CategoryService);
this.DataContext = this;
}
public ArtistListViewModel Alvm {
get; private set;
}
public CategoryListViewModel Clvm {
get; private set;
}
}
The ViewModel for the categories:
public class CategoryListViewModel {
private ICategoryService categoryService;
public CategoryListViewModel(ICategoryService categoryService) {
this.categoryService = categoryService;
Categories = new ObservableCollection<CategoryViewModel>();
UpdateCategories();
}
public ObservableCollection<CategoryViewModel> Categories {
get; set;
}
public void UpdateCategories() {
Categories.Clear();
foreach(var cat in categoryService.GetAllCategories()) {
Categories.Add(new CategoryViewModel(cat));
}
}
}
回答1:
Since DataGridComboBoxColumn or any other supported data grid columns are not part of visual tree of datagrid so they don't inherit the DataContext of datagrid. Since, they don't lie in visual tree so any try to get DataContext using RelativeSource won't work.
Solution - You can create a proxy element to bind the data context of window; use that proxy element to bind the ItemsSource of DataGridComboBoxColumn.
<Grid>
<Grid.Resources>
<FrameworkElement x:Key="ProxyElement" DataContext="{Binding}"/>
</Grid.Resources>
<ContentControl Visibility="Collapsed" Content="{StaticResource ProxyElement}"></ContentControl>
<DataGrid x:Name="datagrid" Grid.Row="1" AutoGenerateColumns="False" ItemsSource="{Binding Alvm.Artists}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" IsReadOnly="True" Binding="{Binding Id}" />
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Email" Binding="{Binding Email}" />
<DataGridComboBoxColumn Header="Category" SelectedItemBinding="{Binding Category}"
ItemsSource="{Binding DataContext.Clvm.Categories, Source={StaticResource ProxyElement}}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
回答2:
You can bind to the DataGrids DataContext by using an ElementName Binding:
<DataGrid x:Name="datagrid" Grid.Row="1" AutoGenerateColumns="False" ItemsSource="{Binding Alvm.Artists}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" IsReadOnly="True" Binding="{Binding Id}" />
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Email" Binding="{Binding Email}" />
<DataGridComboBoxColumn Header="Category" SelectedItemBinding="{Binding Category}"
ItemsSource="{Binding Path=DataContext.Clvm.Categories, ElementName=datagrid}" />
</DataGrid.Columns>
</DataGrid>
Note that you have to give the DataGrid a name for that to work.
Another option is to bind to an Ancestor. With this solution you dont have to give the DataGrid a name, but it is more complex:
<DataGridComboBoxColumn Header="Category" SelectedItemBinding="{Binding Category}"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.Clvm.Categories}" />
来源:https://stackoverflow.com/questions/34102927/wpf-xaml-binding-work-with-real-datacontext