Dot Net For All

WPF Self and AncestorType Relativebinding in DataGrid

In this article I will discuss about the Relativebinding in WPF with C# code example. This type of binding can be used as an alternative to the data context binding. This binding makes the binding bit easier.

You can read about data bindings in WPF in previous articles at the below links:

  1. Data binding in WPF
  2. Data binding modes in WPF

 

Relative source is an markup extension which can be used to point to an object in the XAML. This binding can be used to set declarative binding in the XAML as we will see in the coming example.

Here I will take a simple example of binding the data to the data grid in XAML and deleting the data from grid using the RelativeBindings, Self and AncestorType. It is a very practical example which many developers encounter in their day to day programming in WPF and XAML.

Here I will demo two type of RelativeBindings and their practical implementations.

Please see the figure below where I have a data grid which I am populating with the data from a data source.

DataGrid Binding Demoing Self and AncestorType RelativeBinding

 

Before going further I will show the back end code and other supporting code to display data in this screen.

 

   public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            List<Customer> cust = new List<Customer>() {
                new Customer() { FirstName = "Vikram", Gender = "M", ID = 1, LastName = "Chaudhary" },
                new Customer() { FirstName = "Prasad", Gender = "M", ID = 2, LastName = "M" },
                new Customer() { FirstName = "Steve", Gender = "M", ID = 3, LastName = "Smith" },
                new Customer() { FirstName = "Madhuri", Gender = "F", ID = 4, LastName = "Sharma" },
                new Customer() { FirstName = "Larry", Gender = "M", ID = 5, LastName = "Singh" },
            };
            Customers = new ObservableCollection<Customer>(cust);
            DeleteCustomer = new RelayCommand<Customer>(OnDeleteCustomer);
        }


        public ObservableCollection<Customer> Customers
        {
            get { return (ObservableCollection<Customer>)GetValue(CustomersProperty); }
            set { SetValue(CustomersProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Customers.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CustomersProperty =
            DependencyProperty.Register("Customers", typeof(ObservableCollection<Customer>),
                typeof(MainWindow), new PropertyMetadata(null));


        public RelayCommand<Customer> DeleteCustomer
        {
            get { return (RelayCommand<Customer>)GetValue(DeleteCustomerProperty); }
            set { SetValue(DeleteCustomerProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DeleteCustomer.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DeleteCustomerProperty =
            DependencyProperty.Register("DeleteCustomer", typeof(RelayCommand<Customer>), typeof(MainWindow), new PropertyMetadata(null));


        public void OnDeleteCustomer(Customer cust)
        {
            Customers.Remove(cust);
        }
    }

    public class Customer
    {
        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Gender { get; set; }     
    }


    public class RelayCommand<T> : ICommand where T: class
    {
        Action<T> localTargetAction;
        Func<bool> localTargetCanExecuteChangedMethod;

        public RelayCommand(Action<T> action)
        {
            localTargetAction = action;
        }

        public RelayCommand(Action<T> action, Func<bool> canExecute)
        {
            localTargetAction = action;
            localTargetCanExecuteChangedMethod = canExecute;
        }

        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }

        public event EventHandler CanExecuteChanged;

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

        public void Execute(object parameter)
        {
            T para = parameter as T;       
            localTargetAction(para);
        }
    }

Now as we see in the figure 1 above. I have bind the data using the RelativeSource property and Setting it to self. This will set the MainWindow.cs as the dataContext of the MainWindow.xaml.

Customers is observable collection property present in the MainWindow.cs. This property is bound to the DataGrid which in turn will display the data in the Grid.

Now to delete the data from the grid I have a DeleteCustomer depedency property defined in the MainWindow.cs. I have a delete button for each row of the data grid. But since each row in the datagrid in bound to the Customer object. Using simple priciple of data binding hierarchy the button will try to find the DeleteCustomer in the Customer object.

But since we know that the DeleteCommand is present in the MainWindow.cs which is the DataContext of the DataGrid. We will use the RelativeSource property set to AncestorType=DataGrid. This will help the xaml parser to navigate up the visual tree and find a DataGrid. And since we can use any of the property of the grid once we get the reference of the Grid object. We have used the Path =  DataContext.DeleteCustomer. DataContext is the property of DataGrid which is set to the MainWindows.cs.

All this you can find in the pointer 2 of the figure above.

With the help of all the process we are able to find the DeleteCommand from the MainWindow.cs which is parent binding.

Now if we click the Delete button we can see that the record is deleted from the Grid.

Conclusion:

In this article I have shown how relative source property can be used to bind the data and without using DataContext and moving away from the usual binding hierarchy of the class and objects.

 

Top career enhancing courses you can't miss

My Learning Resource

Excel your system design interview