Editing Tasks

Its all well and good to be able to see the status of the tasks, but it's time to start adding features to the application that allow the user to add, edit or delete a task. The first step is to add the ability to edit tasks.

Edit Tasks Form

Add a new form to the project and name it AddEditTaskForm, we will re-use this form later for adding new tasks on the following page.

Add the following controls:

  • A TextBox named titleTextBox
  • A DateTimePicker named dueDatePicker
  • A ComboBox named priorityComboBox
  • A TextBox named descriptionTextBox
  • A CheckBox named isCompletedCheckBox
  • A Button named okButton with the DialogResult set to OK
  • A Button named cancelButton with the DialogResult set to CANCEL

Add the labels and place the controls as shown in the screenshot:

The new form design for editing tasks

Now we need to wire the UI elements up. Open the code view of AddEditTaskForm and add the following code which adds a private Tasks property which we use to store the data from the dialog UI elements, and to set the values in the dialog.

private Tasks.Tasks _dataContext;

public Tasks.Tasks DataContext
{
    get
    {
        this._dataContext.Task = this.titleTextBox.Text;
        this._dataContext.DueDate = this.dueDatePicker.Value;
        this._dataContext.Details = this.descriptionTextBox.Text;

        if (this.isCompletedCheckBox.Checked)
        {
            this._dataContext.Done = 1;
        }
        else
        {
            this._dataContext.Done = 0;
        }

        this._dataContext.Priority = ((KeyValuePair<Int64, String>)this.priorityComboBox.SelectedItem).Key;

        return this._dataContext;
    }
    set
    {
        this._dataContext = value;
        this.titleTextBox.Text = this._dataContext.Task;
        if (this._dataContext.DueDate.HasValue)
        {
            this.dueDatePicker.Value = this._dataContext.DueDate.Value;
        }
        else
        {
            this.dueDatePicker.Value = DateTime.Today;
        }
        this.descriptionTextBox.Text = this._dataContext.Details;

        if (this._dataContext.Done == 0)
        {
            this.isCompletedCheckBox.Checked = true;
        } 
        else
        {
            this.isCompletedCheckBox.Checked = false;
        }

        this.priorityComboBox.Items.Clear();
        this.priorityComboBox.DisplayMember = "Value";
        foreach (var item in Tasks.Tasks.GetAvailablePriorities())
        {
            this.priorityComboBox.Items.Add(item);
            if (item.Key == this._dataContext.Priority)
            {
                this.priorityComboBox.SelectedItem = item;
            }
        }
    }
}

Switch to TasksPartial.cs and add a new method which is a lookup method that returns the available priorities as a dictionary which is used to populate the ComboBox which the user uses to chose a priority level.

public static IReadOnlyDictionary<Int64, String> GetAvailablePriorities()
{
    return new System.Collections.ObjectModel.ReadOnlyDictionary<Int64, String>(Tasks._priorityLookup);
}

Next switch to MainForm.cs and make the following changes. First specify that we are going to use a collection class by adding

using System.Collections.Generic;

Then add two private fields, the first of which is used to store a list of the tasks. The second is used to store a reference to our data source.

private List<Tasks.Tasks> _data;
private BindingSource _dataSource;

Finally we need to edit loadButton_Click to use those new variables.

private void loadButton_Click(object sender, EventArgs e)
{
    // snipped code

    this.CustomizeDataGridView();
    Tasks.Tasks.ParsePrioritiesTable(this._dataModule.DataAdapter.GetTable<DATutorial.Tasks.Priorities>());

    this._data = (from x in this._dataModule.DataAdapter.GetTable<Tasks.Tasks>() select x).ToList();
    this._dataSource = new BindingSource();
    this._dataSource.DataSource = this._data;

    this.tasksDataGridView.DataSource = this._dataSource;
}

Add an Edit Button

Add a new button to MainForm called editButton with the title Edit Task. This will be used to edit the selected task.

Edit button added to the UI

Double click on the button and add the following code which creates a Task called taskToEdit

private void editButton_Click(object sender, EventArgs e)
{
    Tasks.Tasks taskToEdit = (Tasks.Tasks)this._dataSource.Current;

    using (var form = new AddEditTaskForm())
    {
        form.DataContext = taskToEdit;

        if (form.ShowDialog() != DialogResult.OK)
        {
            return;
        }

        taskToEdit = form.DataContext;
    }

    this._dataModule.DataAdapter.UpdateRow(taskToEdit);
}

Now when you run the app, press the load button to load the data and then press the edit button.

Editing an existing task

Change the priority from Low to High and click OK.

Editing an existing task

The user can now edit their task, but if they quit the app and restart they will find the data has reverted back to its original form. At present all changes the user makes are only applied to the local data. To make the changes permenant we need to apply them to the server.

Applying the Edits

To apply any changes the user makes to the data we need to call the ApplyChanges method of the DataModule class. For the purposes of this tutorial we will only apply the changes when the user actively presses a button.

Add a new button to the MainForm called applyUpdatesButton with the title Apply Updates.

Newly added Apply Updates button

Double click on the button and add the following code to the applyUpdatesButton_Click event handler.

private void applyUpdatesButton_Click(object sender, EventArgs e)
{
    this._dataModule.DataAdapter.ApplyChanges();
}

Repeat the earlier change to the tasks priority. Then press the Apply Updates button, quit the app, restart it and press Load Data. You will find that the change has been persisted. It is worth noting that if the network connection disappears pressing the Apply Updates button will cause an System.Net.Sockets.SocketException exception to be thrown which you should handle.

When to Apply Updates?

The right time to apply updates back to the server will depend very much on what type of application you are developing. You can call ApplyUpdates after every change to a table if you need to, however, it is more efficient to batch changes together before applying them.

Next we'll tackle Adding a new task.