WPF datagrid:添加行时查找控件

时间:2013-08-22 16:29:53

标签: c# wpf datagrid

所以,基本上我有一个我在Datagrid中跟踪的作业列表。在那个数据网格中,我有一个按钮,我想在作业运行时成为“取消”按钮,否则就是“重试”按钮。

所以,我已经将按钮添加到我的网格中:

<DataGridTemplateColumn x:Name="JobActionColumn" Header="">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Grid>
                <Button Click="JobActionButton_Click" Content="Resend" Name="JobActionButton" Height="18" Width="45" Margin="0,0,0,0" />
            </Grid> 
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

在代码中,我将对象添加到ObservableCollection中以将其添加到网格中:

    _jobs.Add(job);
    CollectionViewSource jobViewSource = this.FindViewSource("JobViewSource");
    jobViewSource.View.Refresh(); // Ensure that the new job appears at the top of the grid.
    JobDataGrid.SelectedItem = job;

    // Note: The Controller.Completed event handler disposes the controller object.
    Controller controller = new Controller(_historyContext);
    _controllers.Add(controller);
    controller.Completed += Controller_Completed;
    controller.Process(job);

    GetGridButton("JobActionButton", job).Content = "Cancel";

GetGridButton是:

    private Button GetGridButton(string name, Job job)
    {            
        var selectedRow = (DataGridRow)JobDataGrid.ItemContainerGenerator.ContainerFromItem(job);

        return ExtensionMethods.FindVisualChildren<Button>(selectedRow).First(x => x.Name == name);            
    }

我已确认 GetGridButton 适用于已存在的行。问题是,当您向基础数据集添加新行并调用它时,它无法找到 DataGridRow 。我认为这是因为它尚未创建。因此,通过观察事件,看起来 LoadingRow 事件将是一个很好的候选人:

    private void JobDataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
    {
        Job job = (Job)e.Row.Item;

        if (_controllers.FirstOrDefault(x => x.Job == job) != null)
        {
            var y = ExtensionMethods.FindVisualChildren<Button>(e.Row);
            Button button = ExtensionMethods.FindVisualChildren<Button>(e.Row).First(x => x.Name == "JobActionButton");
            button.Content = "Cancel";
        }
    }

所以,现在有一个 DataGridRow 对象传递给 FindVisualChildren ,但它仍然找不到任何按钮。那么,有没有办法让我在添加的行上访问此按钮?

1 个答案:

答案 0 :(得分:0)

使用WPF的首选方法是MVVM

这是我对你所描述的内容的看法:

<Window x:Class="MiscSamples.MVVMDataGrid"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MVVMDataGrid" Height="300" Width="300">
    <DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False"
              CanUserAddRows="False">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Name}"/>
            <DataGridTemplateColumn>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Grid>
                            <Button Command="{Binding CancelCommand}" Content="Resend" 
                                    Height="20" Width="45" Margin="0,0,0,0" x:Name="btn" />
                        </Grid>

                        <DataTemplate.Triggers>
                            <DataTrigger Binding="{Binding IsRunning}" Value="True">
                                <Setter TargetName="btn" Property="Content" Value="Cancel"/>
                            </DataTrigger>
                        </DataTemplate.Triggers>

                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</Window>

代码背后:

public partial class MVVMDataGrid : Window
{
    public MVVMDataGrid()
    {
        InitializeComponent();

        DataContext = Enumerable.Range(1, 5)
                                .Select(x => new Job {Name = "Job" + x})
                                .ToList();
    }
}

数据项:

public class Job: PropertyChangedBase
{
    public string Name { get; set; }

    private bool _isRunning;
    public bool IsRunning
    {
        get { return _isRunning; }
        set
        {
            _isRunning = value;
            OnPropertyChanged("IsRunning");
        }
    }

    public Command CancelCommand { get; set; }

    public Job()
    {
        CancelCommand = new Command(() => IsRunning = !IsRunning);
    }
}

PropertyChangedBase类(MVVM助手类):

public class PropertyChangedBase:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

命令类(MVVM Helper类):

 //Dead-simple implementation of ICommand
    //Serves as an abstraction of Actions performed by the user via interaction with the UI (for instance, Button Click)
    public class Command : ICommand
    {
        public Action Action { get; set; }

        public void Execute(object parameter)
        {
            if (Action != null)
                Action();
        }

        public bool CanExecute(object parameter)
        {
            return IsEnabled;
        }

        private bool _isEnabled = true;
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                _isEnabled = value;
                if (CanExecuteChanged != null)
                    CanExecuteChanged(this, EventArgs.Empty);
            }
        }

        public event EventHandler CanExecuteChanged;

        public Command(Action action)
        {
            Action = action;
        }
    }

结果:

enter image description here

  • 请注意我如何利用DataBinding来简化代码,并且无需在Visual Tree中查找元素,并在过程代码中对其进行操作。
  • 通过使用抽象按钮功能的Command,逻辑与View完全分离。
  • Code Behind中没有一行代码。只有样板条生成样本条目。
  • 将我的代码复制并粘贴到File -> New Project -> WPF Application中,然后自行查看结果。