Pergunta

I'm using Silverlight 5 with MVVM.

I have a ViewModel that is a Singleton. The ViewModel exposes a PointCollection that I am using to draw a Polyline in one of my views.

If I try to draw the same Polyline in a second view, by databinding to the PointCollection again, I get a "value does not fall within the expected range" exception.

As far as I could find out (with my limited Silverlight knowledge), this is caused by the fact that PointCollections are not shareable.

Is there a workaround? How can I get a second Polyline drawn that is identical to the first? I want to databind two Polylines to one PointCollection at the same time.

Edit: I haven't found a solution, but someone with the same problem here. According to Microsoft:

This MSDN page mentions that some objects are not shareable and will genereate a "value out of range" exception. http://msdn.microsoft.com/en-us/library/system.windows.resourcedictionary(VS.95).aspx

The PointCollection page also mentions that it is not shareable. http://msdn.microsoft.com/en-us/library/system.windows.media.pointcollection(VS.95).aspx

Currently, this is by design behavior. However, we are evaluating this to see whether we can either change the behavior or at least the exception text.

Foi útil?

Solução

Have a look at this question: Why doesn't this data binding work?

And at this one too: 2nd time binding to PointCollection not being rendered

As you gave little details I am not quite sure what is going on but these posts might help out. If not, please post your code.

I did some testing and the best solution I can think of is this:

using System.ComponentModel;
using System.Windows;
using System.Windows.Media;

namespace SilverlightApplication6
{
    public class DemoVM : INotifyPropertyChanged
    {
        #region PointsClone Property
        private PointCollection _pointsClone;
        public PointCollection PointsClone
        {
            get
            {
                return _pointsClone;
            }
            set
            {
                if (_pointsClone != value)
                {
                    _pointsClone = value;
                    OnPropertyChanged("PointsClone");
                }
            }
        }
        #endregion

        #region Points Property
        private PointCollection _points;
        public PointCollection Points
        {
            get
            {
                return _points;
            }
            set
            {
                if (_points != value)
                {
                    _points = value;
                    PointsClone.Clear();
                    foreach (var point in _points)
                    {
                        PointsClone.Add(point);
                    }
                    OnPropertyChanged("Points");
                }
            }
        }
        #endregion

        public DemoVM()
        {
            PointsClone = new PointCollection();
            Points = new PointCollection();
        }

        public void AddPoint(Point point)
        {
            Points.Add(point);
            PointsClone.Add(point);
        }

        public void ClearPoints()
        {
            Points.Clear();
            PointsClone.Clear();
        }


        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            var p = PropertyChanged;
            if (p != null)
            {
                p(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Bind one PolyLine.Points to Points and the other PolyLine.Points to PointsClone.

It is a bit ugly because it will break when you use vm.Points.Add(point) instead of vm.AddPoint(point). By applying proper encapsulation you might be able to solve that.

Outras dicas

I found a solution here: duplicate the PointCollection in the getter.

    private PointCollection sourcePoints;
    public PointCollection SourcePoints
    {
        get
        {
            // create a new instance of PointCollection for binding
            PointCollection newPoints = new PointCollection();
            foreach (Point p in sourcePoints)
            {
                newPoints.Add(p);
            }
            return newPoints;
        }

Maybe your PointCollection is Freezed and that's making the trouble.

MSDN:

Freezable Features: Because it inherits from the Freezable class, the PointCollection class provides several special features: PointCollection objects can be declared as resources, shared among multiple objects, made read-only to improve performance, cloned, and made thread-safe. For more information about the different features provided by Freezable objects, see the Freezable Objects Overview.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top