RadiantQ WPF Gantt
Binding to an XML file
Previous Topic  Next Topic 

Use this option when you choose to save the project information in an XML file, rather than in a database like SQL Server.


It's very easy to setup such a binding using the built-in TaskInfo type to represent each task. You will then simply have to persist a list of these TaskInfo instances in XML.


This topic provides you minimal code to help you understand the concepts, please refer to the GanttControlXmlFileDataSource sample to see the full source code.


Follow these steps to create such an application:


Step 1: Create the control


Create an empty WPF application and add this to the MainPage XAML:


<gantt:GanttControl x:Name="ganttControl" Width="800" Height="600" />


Step 2: Load the file


Add a "Open" button to the page and in it's event handler do the following to open a file and bind it's contents to the ganttControl.


private void Open_Click(object sender, RoutedEventArgs e)

{

    // Create an instance of the open file dialog box.

    OpenFileDialog openFileDialog1 = new OpenFileDialog();


    openFileDialog1.Filter = "XML Files (.xml)|*.xml";


    // Show the dialog

    bool? userClickedOK = openFileDialog1.ShowDialog();


    // Process input if the user clicked OK.

    if (userClickedOK == true)

    {

        try

        {

               // TaskInfo is a type provided by the library to represent a task.

            XmlSerializer serializer = new XmlSerializer(typeof(TaskInfo[]));


            // Open the selected file to read.

             using (System.IO.Stream fileStream = openFileDialog1.OpenFile())

                    {

                        // Read the list of TaskInfos

                        TaskInfo[] taskItemsArray = serializer.Deserialize(fileStream) as TaskInfo[];

                        // Copy it into an editable collection, so we can add and delete TaskInfos.

                        List<TaskInfo> taskItems = new List<TaskInfo>();

                        foreach (TaskInfo ti in taskItemsArray)

                        {

                            taskItems.Add(ti);

                        }

                        // Assign this as the GanttControl's ItemsSource.

                        this.ganttControl.ItemsSource = taskItems;



                       if (taskItems.Count > 0)

                   {

                               // Set up an anchor time so that the gantt chart will scroll to the appropriate position

                               // to show the loaded tasks

                               this.ganttControl.GanttChartView.AnchorTime = taskItems[0].StartTime;

                   }

            }


        }

        catch (IOException){...}

        catch (SerializationException){...}

    }

}


You will now be able to move, connect and edit other properties of any existing tasks.


Step 3: Adding tasks


Add a "Add Task" button to the page and in it's event handler do the following:


private void Add_Click(object sender, RoutedEventArgs e)

{

    // Create a new task and add it to the control.

    TaskInfo newTask = new TaskInfo() { ID = this.ganttControl.Model.GetNewID(), StartTime=TimeComputingUtils.ToUtcKind(DateTime.Today), Effort=TimeSpan.FromDays(1) };

    // Note that this will also add the new item to the bound list.

    this.ganttControl.AddNewItem(newTask);

}


Step 4: Inserting tasks


To insert as a sibling below a specific task:


        private void Insert_Click(object sender, RoutedEventArgs e)

        {

            this.ganttControl.InsertNewItemAsSiblingBelow(

                new TaskInfo() { ID = this.ganttControl.Model.GetNewID(), StartTime = TimeComputingUtils.ToUtcKind(DateTime.Today), Effort = TimeSpan.FromDays(1), Name="New Task" },

                // Use -1 to insert on top of the list

                destinationIndex,

                // true will also add the task to the bound list (if the bound list implements IList)

                // If the bound list does not implement IList, specify false here and then add the CustomTask manually to the bound list.

                true);

        }


To insert as a child of a specific task:


        private void InsertAsChild_Click(object sender, RoutedEventArgs e)

        {

            this.ganttControl.InsertNewItemAsChildOf(

                new TaskInfo() { ID = this.ganttControl.Model.GetNewID(), StartTime = TimeComputingUtils.ToUtcKind(DateTime.Today), Effort = TimeSpan.FromDays(1), Name = "New Task" },

                destParentIndex,

                // true will also add the task to the bound list (if the bound list implements IList)

                // If the bound list does not implement IList, specify false here and then add the CustomTask manually to the bound list.

                true);

        }


Step 5: Deleting tasks


Add a "Delete Selected" button to the page and in it's event handler do the following:


private void Delete_Click(object sender, RoutedEventArgs e)

{

    // Get the selected activity.

    IActivityView activityview = this.ganttControl.SelectedActivityView;

    if (activityview != null)

    {

        // Remove that activity from the GanttControl.

        int id = activityview.Activity.ID;

         // RemoveActivity method will remove the specified activity's children as well.

         IList<IActivity> removedTasks = this.ganttControl.RemoveActivity(id);


        // Also remove that from the bound source.

        List<TaskInfo> taskinfos = this.ganttControl.ItemsSource as List<TaskInfo>;


         foreach (IActivity task in removedTasks)

         {

              taskinfos.Remove(((DataBoundActivity)task).DataSource as TaskInfo);

         }

    }

}


Step 6: Indenting and Outdenting


Add Indent and Outdent buttons to the page and in their handler do this:


private void Indent_Click(object sender, RoutedEventArgs e)

{

    IActivityView activityview = this.ganttControl.SelectedActivityView;

    if(activityview != null)

        // Makes this activity a child of the activity right above it.

        this.ganttControl.Indent(activityview);

}


private void Outdent_Click(object sender, RoutedEventArgs e)

{

    IActivityView activityview = this.ganttControl.SelectedActivityView;

    if(activityview != null)

        // Makes this activity a sibling of it's current parent.

        this.ganttControl.Outdent(activityview);

}


Note that you can also select the activity in the gantt table and move them to a different location within the table.


Step 7: Saving the file


Now, to finally save the changes made, add a "Save" button, in whose handler do this:


private void Save_Click(object sender, RoutedEventArgs e)

{

    // Save the TaskInfos into an XML file.

    bool? result = xmlDialog.ShowDialog();


    if (result == true)

    {

        try

        {

            using (Stream fileStream = xmlDialog.OpenFile())

            {

                // Before saving the tasks, sort them by SortOrder, so that the next time they are viewed

                // they are ordered correctly.

                List<TaskInfo> taskinfos = this.ganttControl.ItemsSource as List<TaskInfo>;

                IOrderedEnumerable<TaskInfo> orderedTasks = taskinfos.OrderBy(task => task.SortOrder);


                TaskInfo[] taskItemsArray = orderedTasks.ToArray();


              

                  XmlSerializer serializer = new XmlSerializer(typeof(TaskInfo[]));

                  // Write the list of TaskInfos into the file

                  serializer.Serialize(fileStream, taskItemsArray);

            }

        }

        catch (IOException)

        {

            MessageBox.Show("Cannot save data to specified file.", "Error", MessageBoxButton.OK);

            return;

        }

    }

}


Step 8: Listening to changes


The TaskInfo type implements INotifyPropertyChanged interface. Listen to it's PropertyChanged event which gets fired when any property changes.


More on this topic is discussed here.



� RadiantQ 2009 - 2019. All Rights Reserved.