WPF C#:如何单独控制DataGrid每行的ProgressBar
如何单独控制DataGrid中每行的ProgressBar?
问题根源分析
你的核心问题出在数据模型设计和绑定逻辑上:
- 当前ViewModel里的
PercentageOfFrame是单个全局属性,而DataGrid每行需要独立的进度值,共用一个属性必然导致所有进度条同步变化。 - XAML中ProgressBar的绑定错误:用
RelativeSource指向DataGridRow,但Row的DataContext是数组中的字符串,根本没有PercentageOfFrame属性,绑定自然失效。 - 后台直接操作UI元素的方式错误:
dg.FindName("progressbar")找不到行模板内的ProgressBar,因为每个行模板的控件都是独立实例,不属于DataGrid的命名空间。
解决方案步骤
1. 创建行数据实体类
每个DataGrid行对应一个独立的实体,包含自身的进度属性:
public class CmdLine : INotifyPropertyChanged { private string _commandText; private int _percentage; public string CommandText { get => _commandText; set { _commandText = value; NotifyPropertyChanged(nameof(CommandText)); } } public int Percentage { get => _percentage; set { _percentage = value; NotifyPropertyChanged(nameof(Percentage)); } } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
2. 修改ViewModel,使用ObservableCollection存储行数据
替换原有的字符串数组,改用支持变更通知的集合类型:
public class CMD_VM : INotifyPropertyChanged { private ObservableCollection<CmdLine> _cmdLines; private int _numberOfFrame; public ObservableCollection<CmdLine> CmdLines { get => _cmdLines; set { _cmdLines = value; NotifyPropertyChanged(nameof(CmdLines)); } } public int NumberOfFrame { get => _numberOfFrame; set { _numberOfFrame = value; NotifyPropertyChanged(nameof(NumberOfFrame)); } } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public CMD_VM() { CmdLines = new ObservableCollection<CmdLine>(); // 初始化时可填充命令数据,示例: // CmdLines.Add(new CmdLine { CommandText = "执行命令1", Percentage = 0 }); } }
3. 修正XAML绑定
让ProgressBar直接绑定到当前行实体的Percentage属性:
<DataGrid x:Name="Datagrid_CmdLines" SelectionUnit="Cell" HeadersVisibility="None" ItemsSource="{Binding CmdLines}" Margin="52,308,0,0" AutoGenerateColumns="False" Width="635" Height="393" HorizontalAlignment="Left" VerticalAlignment="Top" Background="#FFEEEEEE" Grid.Row="1"> <DataGrid.RowStyle> <Style TargetType="DataGridRow"> <Setter Property="IsHitTestVisible" Value="False"/> </Style> </DataGrid.RowStyle> <DataGrid.Columns> <!-- 命令文本列 --> <DataGridTextColumn Width="*" Binding="{Binding CommandText}"/> <!-- 进度条列 --> <DataGridTemplateColumn Width="150"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ProgressBar Value="{Binding Percentage}" Minimum="0" Maximum="100" Height="20"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
4. 修改后台控制逻辑
通过ViewModel中的数据实体更新进度,而非直接操作UI:
private void ColorRow(System.Windows.Controls.DataGrid dg) { // 校验索引有效性 if (cmdvm.NumberOfFrame <= 0 || cmdvm.NumberOfFrame > cmdvm.CmdLines.Count) return; // 获取目标行的实体对象 var targetCmdLine = cmdvm.CmdLines[cmdvm.NumberOfFrame - 1]; // 更新该行的进度值 targetCmdLine.Percentage = registers[61]; // 可选:设置行背景色 DataGridRow row = (DataGridRow)dg.ItemContainerGenerator.ContainerFromIndex(cmdvm.NumberOfFrame - 1); if (row != null) { row.Background = brush; } }
关键要点
- 每个行对应独立的数据实体,确保进度值互不干扰
- 使用
ObservableCollection代替数组,自动同步集合变更到UI - 遵循MVVM模式,通过修改数据属性更新UI,避免直接操作控件
- 修正绑定路径,让控件直接绑定到行数据的对应属性
内容的提问来源于stack exchange,提问作者kivvich
相关产品推荐
相关产品推荐

