c# - WPF DataGrid - 如何在新添加的行上自动设置 EditMode?

标签 c# wpf mvvm datagrid

我有一个程序,到目前为止遵循 MVVM 原则/规则,后面有 0 个代码,我有一个 DataGrid,用户可以在其中添加、编辑或删除代表学生的行。 用户可以通过单击“+”按钮向列表中添加一行,但为了编辑该行,用户必须先单击他刚刚添加的行,这对用户来说不太友好。

我尝试在 EditMode 中设置新添加的行已经有一段时间了,但我所有的尝试要么失败了,要么成功了,但对程序的其余部分产生了一些令人不安的副作用。我在网上查了一下,我发现的解决方案要么看起来有点矫枉过正,要么也有不好的副作用。

我用更少的代码创建了一个类似的程序,以便更容易地显示我的程序和 DataGrid 的结构:

型号

public class Student
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public string PhoneNumber { get; set; }
    public string Address { get; set; }
    public string Email { get; set; }
}

View 模型

public class StudentsViewModel : INotifyPropertyChanged
{
    public StudentsViewModel()
    {
        Students = new ObservableCollection<Student>();
    }

    private ObservableCollection<Student> students;
    public ObservableCollection<Student> Students
    {
        get { return students; }
        set
        {
            students = value;
            NotifyPropertyChanged(nameof(Students));
        }
    }

    private Student selectedStudent;
    public Student SelectedStudent
    {
        get { return selectedStudent; }
        set
        {
            selectedStudent = value;
            NotifyPropertyChanged(nameof(SelectedStudent));
        }
    }

    private ICommand addRow;
    public ICommand AddRow
    {
        get
        {
            if(addRow == null)
            {
                addRow = new RelayCommand(
                    parameter => AddStudent(new Student()),
                    parameter => true
                );
            }
            return addRow;
        }
    }

    private ICommand removeCmd;
    public ICommand RemoveCmd
    {
        get
        {
            removeCmd = new RelayCommand(
                parameter => RemoveStudent(parameter as Student),
                parameter => parameter != null
            );
            return removeCmd;
        }
    }

    private void AddStudent(Student studentToAdd)
    {
        Students.Add(studentToAdd);
    }

    private void RemoveStudent(Student studentToRemove)
    {
        if (Students.Contains(studentToRemove))
        {
            Students.Remove(studentToRemove);
        }
    }

    #region INotify

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void NotifyPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

查看

<Window x:Class="DataGridExample.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:DataGridExample"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="600"
        Width="1000">
    <Window.Resources>
        <local:StudentsViewModel x:Key="StudentsVm"/>
    </Window.Resources>
    <Grid DataContext="{Binding Source={StaticResource StudentsVm}}">
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <DockPanel LastChildFill="False"
                   Background="#FF2C58EC">
            <Button Command="{Binding AddRow}"
                    Height="25"
                    Margin="5">
                <Button.Template>
                    <ControlTemplate>
                        <Image Source="/Images/AddItem.png"/>
                    </ControlTemplate>
                </Button.Template>
            </Button>
            <Button Command="{Binding RemoveCmd}"
                    CommandParameter="{Binding ElementName=StudentDataGrid, Path=SelectedItem}"
                    Height="25"
                    Margin="5">
                <Button.Template>
                    <ControlTemplate>
                        <Image Source="/Images/DeleteItem.png"/>
                    </ControlTemplate>
                </Button.Template>
            </Button>
        </DockPanel>
        <DataGrid ItemsSource="{Binding Students}"
                  SelectedItem="{Binding Source={StaticResource StudentsVm}, Path=SelectedStudent, Mode=TwoWay}"
                  x:Name="StudentDataGrid"
                  ColumnWidth="*"
                  CanUserAddRows="False"
                  CanUserResizeRows="False"
                  CanUserResizeColumns="False"
                  CanUserSortColumns="False"
                  CanUserDeleteRows="False"
                  AutoGenerateColumns="False"
                  Grid.Row="1">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding FirstName, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
                                    Header="First Name">
                </DataGridTextColumn>
                <DataGridTextColumn Binding="{Binding LastName, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
                                    Header="Last Name">
                </DataGridTextColumn>
                <DataGridTemplateColumn Header="Date of Birth">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding DateOfBirth, StringFormat={}{0:dd.MM.yyyy}, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <DatePicker SelectedDate="{Binding DateOfBirth, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
                                        DisplayDate="{Binding DateOfBirth, Mode=OneWay, UpdateSourceTrigger=LostFocus}">
                            </DatePicker>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn Binding="{Binding PhoneNumber, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
                                    Header="Phone Number">
                </DataGridTextColumn>
                <DataGridTextColumn Binding="{Binding Address, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
                                    Header="Address">
                </DataGridTextColumn>
                <DataGridTextColumn Binding="{Binding Email, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
                                    Header="Email">
                </DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

我更希望该解决方案与 MVVM 兼容,但老实说,只要它不会导致其他问题并且不需要大量框架或多个充满代码的文件,我就会感到满意。

我希望结果看起来像 this example但是this is also acceptable只要在单击“+”按钮后不涉及鼠标移动。

最佳答案

我找到了一种方法来实现你想要的,但它似乎不是很可靠,所以请小心使用。首先,您应该连接到 DataGridLoadingRow 事件。

XAML

<DataGrid ...
          LoadingRow="StudentDataGrid_LoadingRow"
          ...>

代码隐藏

private async void StudentDataGrid_LoadingRow(object sender, DataGridRowEventArgs e) {
    // Force asynchrony to run callback after UI has finished loading.
    await Task.Yield();
    // Mark the new row as selected
    StudentDataGrid.SelectedItem = e.Row.Item;
    StudentDataGrid.CurrentCell = new DataGridCellInfo(e.Row.Item, StudentDataGrid.Columns[0]);
    // Enter edit mode
    StudentDataGrid.BeginEdit();
}

通过 async 方法并通过 await Task.Yield() 调用强制它异步执行,您可以让 UI 在之前完成行的加载要求它通过 BeginEdit() 调用开始编辑。

我写这个更多的是作为一个实验,我不知道我是否会推荐这个,但我希望它能在有人找到更好的解决方案时有所帮助。

关于c# - WPF DataGrid - 如何在新添加的行上自动设置 EditMode?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58751096/

相关文章:

wpf - 带有 Entity Framework 项目结构的 MVVM

wpf - 单击父窗口时,如何将父窗口置于子无模式对话框前面

wpf - 我收到以下错误:'#FF000000'不是Color的有效值

wpf - 错误 "Specified element is already the logical child of another element"?

c# - 切换选项卡时关注控件

c# - 如何在 C# 中将“字符添加到多行字符串声明?

windows-phone-7 - MVVM 数据服务和跨 View 模型持久化数据

asp.net-mvc - ASP.NET MVC,Model和ViewModel分离的关注点?

c# - 升级到 3.1 后,ASP.NET Core 未绑定(bind)正文中的参数

c# - 无法在 COM 客户端中添加对 COM 的引用?