Related Dependency Properties in the same UserControl

37 views Asked by At

Consider the following scenario: a UserControl featuring two distinct dependency properties: Customer and Company. Linked to this control is a list of objects from a class, each possessing properties named Customer and Company, with which these UserControl properties are bound. When we alter the SelectedItem of this list, it invokes the callbacks for both dependency properties (OnCustomerChanged and OnCompanyChanged, if both properties changed). Each callback invokes a method, LoadCustomer(Customer, Company). This is our starting point:

public class YourUserControl : UserControl
{
    public static readonly DependencyProperty CustomerProperty =
        DependencyProperty.Register("Customer", typeof(string), typeof(YourUserControl), 
        new PropertyMetadata(OnCustomerChanged));

    public static readonly DependencyProperty CompanyProperty =
        DependencyProperty.Register("Company", typeof(string), typeof(YourUserControl), 
        new PropertyMetadata(OnCompanyChanged));

    public string Customer
    {
        get { return (string)GetValue(CustomerProperty); }
        set { SetValue(CustomerProperty, value); }
    }

    public string Company
    {
        get { return (string)GetValue(CompanyProperty); }
        set { SetValue(CompanyProperty, value); }
    }

    private static void OnCustomerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        LoadCustomer(Customer, Company);
    }

    private static void OnCompanyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        LoadCustomer(Customer, Company);
    }


    private void LoadCustomer(string customer, string company)
    {
        // Logic to load customer with the new values of customer and company
    }
}

So far, everything seems straightforward. However, if, for instance, the SelectedItem transitions from Customer = "1" and Company = "1" to another object with Customer = "2" and Company = "1", only OnCustomerChanged is triggered, resulting in just one call to LoadCustomer (it is OK). Yet, if the transition is to Customer = "3" and Company = "3", it first triggers one callback and then the other, resulting in two calls to LoadCustomer. The initial call originates from OnCustomerChanged with the new Customer but the old Company, followed by another call with the new Customer and Company parameters. This is what I want to avoid, I do not want this call with the old Company.

One approach to circumvent this involves utilizing timers to pause after each update, ensuring both callbacks have completed before invoking LoadCustomer(newCustomer, newCompany).

public class YourUserControl : UserControl
{
    public static readonly DependencyProperty CustomerProperty =
        DependencyProperty.Register("Customer", typeof(string), typeof(YourUserControl), 
        new PropertyMetadata(OnCustomerChanged));

    public static readonly DependencyProperty CompanyProperty =
        DependencyProperty.Register("Company", typeof(string), typeof(YourUserControl), 
        new PropertyMetadata(OnCompanyChanged));

    private DispatcherTimer timer;

    public string Customer
    {
        get { return (string)GetValue(CustomerProperty); }
        set { SetValue(CustomerProperty, value); }
    }

    public string Company
    {
        get { return (string)GetValue(CompanyProperty); }
        set { SetValue(CompanyProperty, value); }
    }

    private static void OnCustomerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = (YourUserControl)d;
        control.ResetTimer();
    }

    private static void OnCompanyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = (YourUserControl)d;
        control.ResetTimer();
    }

    private void ResetTimer()
    {
        if (timer == null)
        {
            timer = new DispatcherTimer(TimeSpan.FromMilliseconds(100), DispatcherPriority.Normal, TimerElapsed, Dispatcher);
        }
        else
        {
            timer.Stop();
            timer.Start();
        }
    }

    private void TimerElapsed(object sender, EventArgs e)
    {
        timer.Stop();
        LoadCustomer(Customer, Company);
    }

    private void LoadCustomer(string customer, string company)
    {
        // Logic to load customer with the new values of customer and company
    }
}

However, I am not particularly fond of this method and believe there may be a more efficient solution, without using triggers or delays. How can I determine when both properties have been updated and subsequently call LoadCustomer just once?

0

There are 0 answers