Home > Software engineering >  INotifyPropertyChanged not working on Gauge (Live Charts)
INotifyPropertyChanged not working on Gauge (Live Charts)

Time:04-12

I'm trying to bind color of Gauge fill property to SolidColorBrush i created code behind. It works fine for progressbar but not for Gauge. The binding works but it doesn't update automatically as same as progressbar. Is that possible to update it while not having to re-plot this? Thank you


XAML:

<Grid Grid.Column="0">
    <lvc:Gauge Grid.Row="2" Grid.Column="0" Margin="5"
               From="0" To="{Binding Path=attaBitrateUP}" Value="{Binding Path=actBitrateUP}" GaugeActiveFill="{Binding Path=up, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
<Grid Grid.Row="2">
   <StackPanel>
     <TextBlock Text="Carrier count:" Height="20" VerticalAlignment="Bottom" Margin="10,0,0,5"/>
          <ProgressBar Height="25" Margin="10,0,10,0" Value="{Binding Path=chartValuesUP}" Maximum="{Binding Path=chartValuesCount}" Foreground="{Binding Path=up}" Background="{Binding Path=down}"/>
   </StackPanel>
</Grid>

Code Behind:

private SolidColorBrush _up = new SolidColorBrush(Colors.OrangeRed);
public SolidColorBrush up 
{
    get { return _up; }
    set 
    {
         _up = value;
         NotifyPropertyChanged();
     }
}

public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

CodePudding user response:

The property GaugeActiveFill has no property changed callback registered. Therefore, it won't detect the change when the data binding is invoked. The library is implemented quite sloppy, frankly said.

But we can fix it ourselves by extending the original Gauge class to register the missing property changed handler:

FixedGauge.cs

public class FixedGauge : Gauge
{
  static FixedGauge()
  {
    GaugeActiveFillProperty.OverrideMetadata(typeof(FixedGauge), new FrameworkPropertyMetadata(default(Brush), OnGaugeActiveFillChanged));
  }

  private PieSlice PART_Pie { get; set; }

  public FixedGauge()
  {
    this.Loaded  = onl oaded;
  }

  private void onl oaded(object sender, RoutedEventArgs e)
  {
    if (TryFindVisualChildElementByName(this, null, out PieSlice pie))
    {
      this.PART_Pie = pie;
    }
  }

  private static void OnGaugeActiveFillChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    => (d as FixedGauge).OnGaugeActiveFillChanged(e.OldValue as Brush, e.NewValue as Brush);

  protected virtual void OnGaugeActiveFillChanged(Brush oldBrush, Brush newBrush)
  {
    if (this.PART_Pie == null)
    {
      return;
    }
    this.PART_Pie.Fill = newBrush;
  }

  public static bool TryFindVisualChildElementByName<TChild>(
    DependencyObject parent,
    string childElementName,
    out TChild resultElement) where TChild : FrameworkElement
  {
    resultElement = null;

    if (parent is Popup popup)
    {
      parent = popup.Child;
      if (parent == null)
      {
        return false;
      }
    }

    for (var childIndex = 0; childIndex < VisualTreeHelper.GetChildrenCount(parent); childIndex  )
    {
      DependencyObject childElement = VisualTreeHelper.GetChild(parent, childIndex);

      if (childElement is TChild frameworkElement)
      {
        if (string.IsNullOrWhiteSpace(childElementName) || frameworkElement.Name.Equals(
          childElementName,
          StringComparison.OrdinalIgnoreCase))
        {
          resultElement = frameworkElement;
          return true;
        }
      }

      if (TryFindVisualChildElementByName(childElement, childElementName, out resultElement))
      {
        return true;
      }
    }

    return false;
  }
}

Then use this new control in place of the original:

<local:FixedGauge Grid.Row="2" Grid.Column="0" Margin="5"
                  From="0" To="{Binding Path=attaBitrateUP}" 
                  Value="{Binding Path=actBitrateUP}" 
                  GaugeActiveFill="{Binding Path=up}" />
  • Related