WPF中如何访问DataGrid内ComboBox的属性及解决绑定为空问题
问题:DataGrid模板列中ComboBox绑定为空且无法后台访问
我希望在DataGrid的DataGridTemplateColumn内的ComboBox中显示数据,但绑定后控件为空,尝试在后台代码中填充数据,却无法通过名称访问该ComboBox。试过切换到GridView,但操作难度比DataGrid更大。
XAML代码
<Window x:Class="ComboDataWPF.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:ComboDataWPF" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" WindowStartupLocation="CenterScreen" Loaded="Window_Loaded"> <Grid> <DataGrid x:Name="MainDataGrid" AutoGenerateColumns="False" ItemsSource="{Binding ALLMYDATA, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"> <DataGrid.Columns> <DataGridTextColumn Header="The Name :" Width="120" Binding="{Binding NAMES, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" /> <DataGridTemplateColumn Header=" Name and Code " Width="150"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ComboBox x:Name="ComboBox1" ItemsSource="{Binding ALLMYDATA, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" SelectedValuePath="{Binding CODE, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" DisplayMemberPath="{Binding NAMES, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" IsTextSearchEnabled="True" IsEditable="True" SelectedIndex="0" BorderBrush="#FFADEEB4" Background="{x:Null}" BorderThickness="1"> <ComboBox.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling"/> </ItemsPanelTemplate> </ComboBox.ItemsPanel> </ComboBox> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> </Grid> </Window>
后台C#代码
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace ComboDataWPF { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { MyerEntities dbms = new MyerEntities(); public ObservableCollection<MyCustomModel> ALLMYDATA { get; set; } = new ObservableCollection<MyCustomModel>(); public class MyCustomModel { public int CODE { get; set; } public string NAMES { get; set; } } public MainWindow() { InitializeComponent(); DataContext = this; } private void Window_Loaded(object sender, RoutedEventArgs e) { ALLMYDATA.Clear(); var RST = dbms.Database.SqlQuery<MyCustomModel>("SELECT CODE,NAMES FROM TCOD_ANBAR").ToList(); foreach (var item in RST) { ALLMYDATA.Add(item); } } } }
问题分析与解决
一、ComboBox为空的原因及修复
ComboBox绑定失败的核心问题是数据上下文错误:
- DataGrid的
ItemsSource绑定的是ALLMYDATA,因此模板列中的每个元素的DataContext是单个MyCustomModel对象,而非窗口本身。 - 原来的
ItemsSource="{Binding ALLMYDATA}"会去当前行的MyCustomModel里找ALLMYDATA属性,而该属性不存在,导致绑定失效。
同时,SelectedValuePath和DisplayMemberPath的用法错误:这两个属性是指定属性名称的字符串,不需要用Binding语法,直接写属性名即可。
修复后的ComboBox XAML:
<ComboBox x:Name="ComboBox1" ItemsSource="{Binding DataContext.ALLMYDATA, RelativeSource={RelativeSource AncestorType=Window}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" SelectedValuePath="CODE" DisplayMemberPath="NAMES" IsTextSearchEnabled="True" IsEditable="True" SelectedIndex="0" BorderBrush="#FFADEEB4" Background="{x:Null}" BorderThickness="1">
- 用
RelativeSource指定绑定源为窗口的DataContext,从而正确获取全局的ALLMYDATA集合。 - 修正
SelectedValuePath和DisplayMemberPath为直接属性名。
二、后台访问ComboBox的方法
由于ComboBox在DataTemplate内部,每个DataGrid行都会生成一个实例,无法直接通过x:Name在后台访问。可以通过以下两种方式处理:
1. 推荐:通过绑定操作(MVVM方式)
将ComboBox需要操作的属性(如SelectedItem、ItemsSource)绑定到ViewModel(这里是MainWindow)的属性,避免直接操作控件。比如在MyCustomModel中添加SelectedItem属性,绑定到ComboBox的SelectedItem,即可在后台通过数据集合操作选中状态。
2. 直接查找控件(仅在必要时使用)
如果必须直接操作ComboBox实例,可以通过DataGrid的ItemContainerGenerator找到对应行,再查找控件:
private void AccessComboBox() { // 获取指定索引的行(示例为第0行) var row = MainDataGrid.ItemContainerGenerator.ContainerFromIndex(0) as DataGridRow; if (row == null) return; // 获取模板列的单元格内容 var cellContent = MainDataGrid.Columns[1].GetCellContent(row); if (cellContent == null) return; // 查找ComboBox var comboBox = (cellContent as FrameworkElement).FindName("ComboBox1") as ComboBox; if (comboBox != null) { // 执行操作,比如更新ItemsSource comboBox.ItemsSource = ALLMYDATA; } }
注意:DataGrid默认开启虚拟化,未加载的行无法通过此方法获取,需确保行已生成后再调用。
内容的提问来源于stack exchange,提问作者Mojtabah
相关产品推荐
相关产品推荐

