Gil Sand
Gil Sand

Reputation: 6040

How to add rows dynamically to a Datagrid in UWP?

I'm trying to achieve exactly what can be seen in Microsoft Access, and for now I'm using a Datagrid but I'm not certain this is the correct tool for the job.

Microsoft Access dynamic addition of rows

When you look at the screenshot, the last row is always empty and whatever it is you want to add ; if you erase one of the rows, all the next ones go up in index and it's all very smooth.

How can that be done in UWP? Do I have to write all the logic from scratch or is there some control that can help with that?

Currently, my idea is that I'll have to check the content of all cells and move them up manually if one is empty, and create a "fake" row that has a placeholder textboxes with "add row" content that automagically change when you write on it, as it creates an extra row underneath.

All that would also require to move items in the bound collection and I can already see nightmarish results. Am I on the right path at all?

Another idea I have is to include a "Delete Row" button in all rows that would delete that row from the collection, which would auto update with binding. And just add a "Add Row" under that creates an empty object in the binding collection, that the user would then edit. It would be smoother but also feels like a hack, and still not that smooth with all the "delete row" buttons everywhere.

Upvotes: 2

Views: 1517

Answers (1)

YanGu
YanGu

Reputation: 3032

There is no API in DataGrid could directly achieve what you want. The idea of adding "Delete Row" button in the DataGrid is feasible, and you can refer to the following code to solve your problem.

  1. DataGrid uses two-way binding. In the last item of the data source, the PersonId is set to "[Add New Row]", and all other propeties are empty.
  2. In the EmployeeGrid_BeginningEdit event, when the last row of the DataGrid is edited, an instance with empty properties will be inserted into the data source.
  3. In the DeleteButton_Click event, you could delete the corresponding instance in the data source.

XAML:

<Grid>
        <StackPanel>
            <controls:DataGrid
                  x:Name="EmployeeGrid"
                  ItemsSource="{x:Bind Persons,Mode=TwoWay}"
                  AutoGenerateColumns="False"
                 GridLinesVisibility="All"
                Width="700"
                Height="800"
                BeginningEdit="EmployeeGrid_BeginningEdit"
                
                >
                <controls:DataGrid.Columns>
                    <controls:DataGridTextColumn Header="PersonId"
                                             Binding="{Binding PersonId}"/>
                    <controls:DataGridTextColumn Header="First Name"
                                             Binding="{Binding FirstName}"/>
                    <controls:DataGridTextColumn Header="Last Name"
                                             Binding="{Binding LastName}"/>
                    <controls:DataGridTextColumn Header="Position"
                                             Binding="{Binding Position}"/>
                    <controls:DataGridTemplateColumn Header="">
                        <controls:DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Button x:Name="DeleteButton" Background="#00000000" Click="DeleteButton_Click">
                                    <Image Source="/Assets/IconDelete.png" Height="30" Width="30" Stretch="UniformToFill" />
                                </Button>
                            </DataTemplate>
                        </controls:DataGridTemplateColumn.CellTemplate>
                    </controls:DataGridTemplateColumn>
                </controls:DataGrid.Columns>
            </controls:DataGrid>
        </StackPanel>
</Grid>

Code behind:

namespace AddRow
{

    public sealed partial class MainPage : Page
    {
        public ObservableCollection<Person> Persons { get; set; }
        public MainPage()
        {
            this.InitializeComponent();
            Persons = new ObservableCollection<Person>()
            {
               new Person
               {
                PersonId = "1", FirstName = "Ronald", LastName = "Rumple",
                Position = "Network Administrator"
               },
               new Person
               {
                PersonId = "2",FirstName = "Brett", LastName = "Banner",
                Position = "Software Developer"
               },
               new Person
               {
                PersonId = "3", FirstName = "Alice", LastName = "Anderson",
                Position = "Accountant"
               },
               new Person
               {
                PersonId = "[Add New Row]", FirstName = null, LastName = null,
                Position = null
               }
            };
        }

  
      

        private void EmployeeGrid_BeginningEdit(object sender, Microsoft.Toolkit.Uwp.UI.Controls.DataGridBeginningEditEventArgs e)
        {
            Person p = new Person
            {
                PersonId = "[Add New Row]",
                FirstName = null,
                LastName = null,
                Position = null
            };
            int x = EmployeeGrid.SelectedIndex;
            int y = Persons.Count;
            if (x + 1 == y)
            {
                Persons.Insert(Persons.Count, p);
            }
        }

        private async void DeleteButton_Click(object sender, RoutedEventArgs e)
        {
            Button button = sender as Button;
            Person p = button.DataContext as Person;
            var messageDialog = new ContentDialog()
            {
                Title = "Warning",
                Content = "Are you sure you want to delete?",
                PrimaryButtonText = "Ok",
                CloseButtonText = "Cancel"
            };
            var result = await messageDialog.ShowAsync();
            if (result == ContentDialogResult.Primary)
            {
                Persons.Remove(p);
            }
        }

       
    }
    public class Person:INotifyPropertyChanged
    {
        private string personId;
        private string firstName;
        private string lastName;
        private string position;
        public string PersonId { 
            get 
            {
                return personId;
            } 
            set 
            {
                personId = value;
                RaisePropertyChanged(nameof(PersonId));
            } 
        }
        public string FirstName
        {
            get
            {
                return firstName;
            }
            set
            {
                firstName = value;
                RaisePropertyChanged(nameof(FirstName));
            }
        }
        public string LastName
        {
            get
            {
                return lastName;
            }
            set
            {
                lastName = value;
                RaisePropertyChanged(nameof(LastName));
            }
        }
        public string Position
        {
            get
            {
                return position;
            }
            set
            {
                position = value;
                RaisePropertyChanged(nameof(Position));
            }
        }      

        public event PropertyChangedEventHandler PropertyChanged;
        public void RaisePropertyChanged([CallerMemberName] string propertyname=null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
        }
    }

}

Result:

enter image description here

Upvotes: 3

Related Questions