Search code examples
c#wpfdependency-properties

How to control the order of Dependecy Properties Initialization in C#


I'm trying to create a TextBox control that has a "Table of values" and an "Index" as dependency properties, were I can changed the Index property and the TextBox will look for the corresponding Value from the Table.

Here's the code:

public class Record
{
    public int Index { get; set; }
    public string Value { get; set; }
}
public class IndexedTextBox : TextBox
{
    public static readonly DependencyProperty TableProperty = DependencyProperty.Register(nameof(Table),
                    typeof(IEnumerable<Record>), typeof(IndexedTextBox));
    public static readonly DependencyProperty IndexProperty = DependencyProperty.Register(nameof(Index),
                    typeof(int), typeof(IndexedTextBox), new PropertyMetadata(0, IndexChangedCallback));

    private static void IndexChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        IndexedTextBox ctl = d as IndexedTextBox;
        int index = (int)e.NewValue;

        if (ctl.Table.Any(t => t.Index == index))
            ctl.Text = ctl.Table.Where(t => t.Index == index).FirstOrDefault().Value;
        else
            ctl.Text = "N/A";
    }

    public IEnumerable<Record> Table
    {
        get => (IEnumerable<Record>)GetValue(TableProperty);
        set => SetValue(TableProperty, value);
    }

    public int Index {
        get => (int)GetValue(IndexProperty);
        set => SetValue(IndexProperty, value);
    }
}

And the XAML code is something like this:

<local:IndexedTextBox Table="{Binding ViewModelTable}" Index="1"/>

Sometimes is works, other times it won't.

I noticed that the 2 properties (Table and Index) are being initialized in random order, and whenever the Index is loaded before the Table the control won't work as expected.

Is there a workaround to that? Can we control the order of the Initialization or there any other thing I should be doing.

I'd greatly appreciate a feedback

Thanks


Solution

  • whenever the Index is loaded before the Table the control won't work as expected ...

    So change the implementation to make it work by for example invoking the callback for both properties and check the state of the control before doing anything, e.g.:

    public class IndexedTextBox : TextBox
    {
        public static readonly DependencyProperty TableProperty = DependencyProperty.Register(nameof(Table),
                        typeof(IEnumerable<Record>), typeof(IndexedTextBox), new PropertyMetadata(null, TableChangedCallback));
    
        public static readonly DependencyProperty IndexProperty = DependencyProperty.Register(nameof(Index),
                        typeof(int), typeof(IndexedTextBox), new PropertyMetadata(0, IndexChangedCallback));
    
        private static void TableChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
            ((IndexedTextBox)d).SetText();
    
        private static void IndexChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
            ((IndexedTextBox)d).SetText();
    
        private void SetText()
        {
            if (Table != null)
            {
                int index = Index;
    
                if (Table.Any(t => t.Index == index))
                    Text = Table.Where(t => t.Index == index).FirstOrDefault().Value;
                else
                    Text = "N/A";
            }
        }
    
        public IEnumerable<Record> Table
        {
            get => (IEnumerable<Record>)GetValue(TableProperty);
            set => SetValue(TableProperty, value);
        }
    
        public int Index
        {
            get => (int)GetValue(IndexProperty);
            set => SetValue(IndexProperty, value);
        }
    }