Question

I have a class (let's call it externalClass) with a ObservableCollection<Point> channel1 inside. (the class itself does NOT implements INotify)

In the MainWindow I have a polyline binded to this externalClass.channel1 that uses a converter from ObservableCollection to PointCollection.

So from the C# I bind DataContext = externalClass; and in the XAML the polyline looks like:

<Polyline Points="{Binding channel1, Converter={StaticResource pointCollectionConverter}}" Stroke="#FF00E100" Name="line" />

I have a test function that works like that:

public void test()
{
   ObservableCollection<Point> newone = new ObservableCollection<Point>();
   for (int i = 0; i < debugCh1.Count; i++)
   {
      Point p1 = debugCh1[i];
      p1.Y = p1.Y + 1;
      newone.Add(p1);
   }
   channel1= newone;
}

If I add a breakpoint in the converter itself I can see that on start-up it is called (and actually the initial values (hard-coded) are displayed. But when I add the test function to a button .. it does nothing (the converter is not called)

Any idea idea of where the notification of the changes is being stopped ???

SOLUTION

After reading the answers and googleling a bit more I came out with the soulition. Id like to post it there for everybody else

So .. The so-called externalClass must inherit from INotifyPropertyChanged and it must implement NotifyPropertyChanged So all and all it must be declared like that:

public class externalClass  : INotifyPropertyChanged
{ 
  ....
    // at some point you have your ObservableCollection<smth> as a property 
    public ObservableCollection<Point> channel1 { get; set; }
  ....
    //at some point you implement NotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string caller)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(caller));
        }
    }
   ....
   //then whenever you need to fire the notification
   [..]do something with channel1
   NotifyPropertyChanged("channel1");

And that's all. If you add a proper binding (as the one I showed in my question) the whole set up is gonna work.. At least mine worked hehehe

Good luck! And thanks to the people that helped me !! :D

Was it helpful?

Solution

Polyline Points probably does not listen to INotifyCollectionChanged when bound. Try exposing Channel1 as a property and raise the INotifyPropertyChanged with "Channel1"

OTHER TIPS

First, you need create your custom class PointCollection:

public class PointCollection : ObservableCollection<Point>
{
    public PointCollection()
    {

    }


    public PointCollection(IEnumerable<Point> points) : base(points)
    {

    }
}

Second, you need create custom Polyline:

public class PolylineDynamic : Shape
{
    private Geometry _polylineGeometry = Geometry.Empty;

    public static readonly DependencyProperty PointsProperty = DependencyProperty.Register(nameof(Points), typeof(PointCollection), typeof(PolylineDynamic), new FrameworkPropertyMetadata(PointsChanged));

    private static void PointsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((PolylineDynamic)d).PointsChanged(e);
    }

    private void PointsChanged(DependencyPropertyChangedEventArgs e)
    {
        if (e.OldValue is PointCollection oldPoints)
            oldPoints.CollectionChanged -= OnPointsChanged;
        if (e.NewValue is PointCollection newPoints)
            newPoints.CollectionChanged += OnPointsChanged;
        UpdatePolyline();
    }

    public PointCollection Points
    {
        get => (PointCollection)GetValue(PointsProperty);
        set => SetValue(PointsProperty, value);
    }

    public static readonly DependencyProperty FillRuleProperty = DependencyProperty.Register(nameof(FillRule), typeof(FillRule), typeof(PolylineDynamic), new FrameworkPropertyMetadata(FillRule.EvenOdd));

    public FillRule FillRule
    {
        get => (FillRule)GetValue(FillRuleProperty);
        set => SetValue(FillRuleProperty, value);
    }

    protected override Geometry DefiningGeometry => _polylineGeometry;

    private void OnPointsChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                var aPoint = e.NewItems.OfType<Point>().Single();
                Add(aPoint, e.NewStartingIndex);
                break;
            case NotifyCollectionChangedAction.Remove:
                Remove(e.OldStartingIndex);
                break;
            case NotifyCollectionChangedAction.Replace:
                var rPoint = e.NewItems.OfType<Point>().Single();
                Replace(rPoint, e.NewStartingIndex);
                break;
        }
    }

    protected void UpdatePolyline()
    {
        if (Points == null || Points.Count < 2)
            _polylineGeometry = Geometry.Empty;
        else
        {
            var pGeometry = GetPathGeometry();
            for (var i = 0; i < Points.Count; i++)
            {
                if (i == 0)
                    continue;
                var startPoint = Points[i - 1];
                var point = Points[i];
                var figure = new PathFigure { StartPoint = startPoint };
                figure.Segments.Add(new LineSegment(point, true));
                pGeometry.Figures.Add(figure);
            }
        }
    }

    private void Add(Point point, int index)
    {
        var pGeometry = GetPathGeometry();
        if (pGeometry.Figures.Count == 0)
        {
            UpdatePolyline();
            return;
        }

        if (index == Points.Count - 1)
        {
            var segment = new LineSegment(point, true);
            var figure = new PathFigure { StartPoint = Points[index - 1] };
            figure.Segments.Add(segment);
            pGeometry.Figures.Add(figure);
        }
        else if (index == 0)
        {
            var segment = new LineSegment(Points[1], true);
            var figure = new PathFigure { StartPoint = point };
            figure.Segments.Add(segment);
            pGeometry.Figures.Insert(0, figure);
        }
        else
        {
            var leftFigure = new PathFigure { StartPoint = Points[index - 1] };
            leftFigure.Segments.Add(new LineSegment(point, true));
            var rightFigure = new PathFigure { StartPoint = point };
            rightFigure.Segments.Add(new LineSegment(Points[index + 1], true));
            pGeometry.Figures.Insert(index - 1, leftFigure);
            pGeometry.Figures.Insert(index, rightFigure);
        }
        InvalidateVisual();
    }

    private void Remove(int index)
    {
        var pGeometry = GetPathGeometry();
        if (!pGeometry.Figures.Any())
        {
            _polylineGeometry = Geometry.Empty;
            InvalidateVisual();
            return;
        }

        if (index == Points.Count - 1 || index == 0)
            pGeometry.Figures.RemoveAt(index);
        else
        {
            var leftFigure = pGeometry.Figures[index - 1];
            var rightFigure = pGeometry.Figures[index];
            pGeometry.Figures.RemoveAt(index - 1);
            rightFigure.StartPoint = ((LineSegment)leftFigure.Segments.Single()).Point;
        }
        InvalidateVisual();
    }

    private void Replace(Point point, int index)
    {
        var pGeometry = GetPathGeometry();
        if (index == 0)
            pGeometry.Figures[0].StartPoint = point;
        else if (index == Points.Count - 1)
            ReplaceSegment(pGeometry.Figures[index - 1], point);
        else
        {
            ReplaceSegment(pGeometry.Figures[index - 1], point);
            pGeometry.Figures[index].StartPoint = point;
        }
        InvalidateVisual();
    }

    private void ReplaceSegment(PathFigure figure, Point point)
    {
        figure.Segments.Clear();
        figure.Segments.Add(new LineSegment(point, true));
    }

    private PathGeometry GetPathGeometry()
    {
        if (_polylineGeometry is PathGeometry pathGeometry)
            return pathGeometry;
        else
        {
            pathGeometry = new PathGeometry { FillRule = FillRule };
            _polylineGeometry = pathGeometry;
            return pathGeometry;
        }
    }
}

If you need more functionality, you can add more)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top