首页 文章

WPF / XAML绑定:使用真正的DataContext

提问于
浏览
1

这是我的XAML代码:

<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>

上面的ComboBox只是用于测试 - 我想看看我是否可以显示我的所有类别并且它运行良好 .

下面的DataGrid是我真正想要的控件 . 我希望将类别ComboBox作为DataGrid的一列 . 但是我在代码片段中这样做的方式显然不起作用,因为列的数据绑定是相对于DataGrid的ItemsSource而不是旧的DataContext . 如何将其切换回绑定?

Control类:

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;
    }
}

类别的ViewModel:

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));
        }
    }
}

2 回答

  • 3

    由于 DataGridComboBoxColumn 或任何其他受支持的数据网格列不是 datagrid 的可视树的一部分,因此它们不会继承 datagridDataContext . 因为,它们不在于可视化树,所以任何试图使用 RelativeSource 都不会起作用 .

    解决方案 - 您可以创建一个代理元素来绑定窗口的数据上下文;使用该代理元素绑定_256284_的 ItemsSource .

    <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>
    
  • 1

    您可以使用 ElementName 绑定绑定到 DataGrids DataContext

    <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>
    

    请注意,您必须为 DataGrid 指定一个名称才能生效 .


    另一个选择是绑定到 Ancestor . 使用此解决方案,您不必为 DataGrid 指定名称,但它更复杂:

    <DataGridComboBoxColumn Header="Category" SelectedItemBinding="{Binding Category}"
          ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.Clvm.Categories}" />
    

相关问题