WPF MVVM中如何访问TabItem内UserControl的DataGrid并绑定数据
实现方案
1. 定义测试结果数据模型
先创建承载测试结果的实体类,实现INotifyPropertyChanged以便后续属性动态更新:
public class NetworkTestResult : INotifyPropertyChanged { private string _name; public string Name { get => _name; set { _name = value; OnPropertyChanged(); } } private string _size; public string Size { get => _size; set { _size = value; OnPropertyChanged(); } } private string _status; public string Status { get => _status; set { _status = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
2. 创建Comp_Item的视图模型(CompItemVM)
这个VM对应单个Comp_Item控件的数据源,包含三个ObservableCollection分别绑定三个DataGrid:
public class CompItemVM : INotifyPropertyChanged { // 对应connDataGrid的数据源 public ObservableCollection<NetworkTestResult> ConnResults { get; } = new ObservableCollection<NetworkTestResult>(); // 对应outDataGrid的数据源 public ObservableCollection<NetworkTestResult> OutResults { get; } = new ObservableCollection<NetworkTestResult>(); // 对应inDataGrid的数据源 public ObservableCollection<NetworkTestResult> InResults { get; } = new ObservableCollection<NetworkTestResult>(); // 电脑名称,用于TabItem的Header显示 private string _computerName; public string ComputerName { get => _computerName; set { _computerName = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
3. 绑定Comp_Item.xaml的DataGrid
修改Comp_Item.xaml,将三个DataGrid的ItemsSource绑定到CompItemVM的对应集合:
<UserControl x:Class="YourNamespace.Comp_Item" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" mc:Ignorable="d"> <Grid> <DataGrid x:Name="connDataGrid" ItemsSource="{Binding ConnResults}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Header="名称" Binding="{Binding Name}"/> <DataGridTextColumn Header="大小" Binding="{Binding Size}"/> <DataGridTextColumn Header="状态" Binding="{Binding Status}"/> </DataGrid.Columns> </DataGrid> <DataGrid x:Name="outDataGrid" ItemsSource="{Binding OutResults}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Header="名称" Binding="{Binding Name}"/> <DataGridTextColumn Header="大小" Binding="{Binding Size}"/> <DataGridTextColumn Header="状态" Binding="{Binding Status}"/> </DataGrid.Columns> </DataGrid> <DataGrid x:Name="inDataGrid" ItemsSource="{Binding InResults}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Header="名称" Binding="{Binding Name}"/> <DataGridTextColumn Header="大小" Binding="{Binding Size}"/> <DataGridTextColumn Header="状态" Binding="{Binding Status}"/> </DataGrid.Columns> </DataGrid> </Grid> </UserControl>
4. 构建DashboardVM并关联CompItemVM集合
在DashboardVM中创建CompItemVM的集合,绑定到TabControl,同时实现测试命令:
public class DashboardVM : INotifyPropertyChanged { // 所有电脑的VM集合,绑定到TabControl public ObservableCollection<CompItemVM> ComputerItems { get; } = new ObservableCollection<CompItemVM>(); // 开始测试的命令 public ICommand StartTestCommand { get; } public DashboardVM() { // 初始化4个电脑的VM ComputerItems.Add(new CompItemVM { ComputerName = "Computer1" }); ComputerItems.Add(new CompItemVM { ComputerName = "Computer2" }); ComputerItems.Add(new CompItemVM { ComputerName = "Computer3" }); ComputerItems.Add(new CompItemVM { ComputerName = "Computer4" }); StartTestCommand = new RelayCommand(ExecuteStartTest); } private void ExecuteStartTest() { // 对Computer1执行ping测试,结果添加到对应的集合 var comp1VM = ComputerItems.FirstOrDefault(vm => vm.ComputerName == "Computer1"); if (comp1VM != null) { // 替换为真实ping逻辑 comp1VM.ConnResults.Add(new NetworkTestResult { Name = "Ethernet", Size = "8 Bytes", Status = "Pass" }); } // 同理可处理其他电脑的测试 } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } // 简单实现RelayCommand(无第三方库时使用) public class RelayCommand : ICommand { private readonly Action _execute; private readonly Func<bool> _canExecute; public event EventHandler CanExecuteChanged; public RelayCommand(Action execute, Func<bool> canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true; public void Execute(object parameter) => _execute(); public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); }
5. 绑定Dashboard.xaml的TabControl
修改Dashboard.xaml,将TabControl绑定到DashboardVM的ComputerItems集合:
<UserControl x:Class="YourNamespace.Dashboard" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:YourNamespace" mc:Ignorable="d"> <Grid> <StackPanel> <Button Content="开始测试" Command="{Binding StartTestCommand}" Margin="10"/> <TabControl ItemsSource="{Binding ComputerItems}"> <TabControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding ComputerName}"/> </DataTemplate> </TabControl.ItemTemplate> <TabControl.ContentTemplate> <DataTemplate> <local:Comp_Item/> </DataTemplate> </TabControl.ContentTemplate> </TabControl> </StackPanel> </Grid> </UserControl>
6. 设置Dashboard的DataContext
在Dashboard构造函数中设置DataContext:
public Dashboard() { InitializeComponent(); DataContext = new DashboardVM(); }
核心思路说明
- 完全遵循MVVM:所有数据操作在VM层完成,不直接操作View控件
- 利用
ObservableCollection的自动通知特性,添加数据后UI自动更新 - 每个
Comp_Item对应独立VM,确保不同Tab数据互不干扰 - 通过集合绑定实现TabControl与多个
Comp_Item的关联,避免硬编码TabItem
内容的提问来源于stack exchange,提问作者Chip Brommer
相关产品推荐
相关产品推荐

