Search code examples
wpfwpfdatagriddependency-properties

Manually update some DataGrid's elements


I have this DataGrid:

<DataGrid x:Name="dgTimeline" Focusable="False" GotFocus="dgTimeline_GotFocus">

So I add columns with a custom class called TimelineControl and bind its Minutes properties with Time%:

for (int i = 0; i <= 30; i++)
{
    FrameworkElementFactory fef = new FrameworkElementFactory(typeof(TimelineControl));
    Binding bTemp = new Binding("Time" + i);
    bTemp.Mode = BindingMode.TwoWay;
    fef.SetValue(TimelineControl.MinutesProperty, bTemp);
    DataTemplate dt = new DataTemplate();
    dt.VisualTree = fef;
    dgTempCol.CellTemplate = dt;

    dgTimeline.Columns.Add(dgTempCol);
}

Here is TimelineControl:

public static DependencyProperty MinutesProperty =
DependencyProperty.Register("Minutes", typeof(string), typeof(TimelineControl),
new PropertyMetadata(OnMinutesChanged));

public string Minutes
{
    get { return (string)GetValue(MinutesProperty); }
    set { SetValue(MinutesProperty, value); }
}

private static void OnMinutesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    Console.WriteLine("foo bar");
}

Latter on I add some rows with:

TimeScale temp;
temp = this.addEvent(temp, 23);
temp = this.addEvent(temp, 24);
temp = this.addEvent(temp, 25);
temp = this.addEvent(temp, 26);

dgTimeline.Items.Add(temp);

private TimeScale addEvent(TimeScale temp, int time)
{
    PropertyInfo propertyInfo = temp.GetType().GetProperty("Time" + (time / 60));

    if (propertyInfo.GetValue(temp, null) != null)
    {
        if (propertyInfo.GetValue(temp, null).ToString().IndexOf((time % 60).ToString()) == -1)
        {
            propertyInfo.SetValue(temp, Convert.ChangeType(propertyInfo.GetValue(temp, null) +
                "," + (time % 60), propertyInfo.PropertyType), null);
        }
    }
    else
    {
        propertyInfo.SetValue(temp, Convert.ChangeType(time % 60, propertyInfo.PropertyType), null);
    }

    return temp;
}

Everything works fine so far, the OnMinutesChanged is triggered just fine and the UI is updated. The problem is that when I try to update something that is on the DataGrid the OnMinutesChanged is not triggered and the UI is not updated.

My objective with OnMinutesChanged is to manually update the UI of the specific elements that were changed. If I call dgTimeline.Items.Refresh() then the whole grid is refreshed and everything works, the OnMinutesChanged is called. The problem is that this grid is updated every second, so call dgTimeline.Items.Refresh() makes the application almost freeze because the number of elements is high (more than 500 easily). I just need to update 3 elements' UI per second, not all the 500, that's why I want to manually do it.

Am I doing the right thing? If yes, why OnMinutesChanged is not being called when I update the grid?


Solution

  • DataGrid uses binding groups to validate the whole row and prevent an invalid state in the underlying object in case one of the properties is assigned an invalid value. This changes the default UpdateSourceTrigger of bindings within cells to Explicit, you can override this by explicitly setting it to PropertyChanged on your binding object.

    Normally the update is invoked if the user finishes editing a row, you however never enter edit mode as you use CellTemplate and not CellEditingTemplate.