Search code examples
wpfmvvminkcanvas

MVVM Binding to InkCanvas


I seem to have ran into a road block. We are using MVVM with Prism and have a View that requires an Ink Canvas. I've create a StrokeCollection that is being bound from my ViewModel to the View. I am able to set the collection from my viewmodel but changes are not coming up to the ViewModel while the user draws. Is there a way to make this work?

My Property in my ViewModel is as follows:

private StrokeCollection _strokes;
public StrokeCollection Signature
{
     get
     {
         return _strokes;
     }
     set
     {
         _strokes = value;
         OnPropertyChanged("Signature");
     }
}

Here is my XAML binding line:

<InkCanvas x:Name="MyCanvas" Strokes="{Binding Signature, Mode=TwoWay}" />

For some reason apparently the InkCanvas never notifies the ViewModel of any change.


Solution

  • The problem with your approach is that you assume the InkCanvas creates the StrokeCollection. It does not - it merely adds and removes items from it. And if the collection isn't available (ie. is null), the binding will fail and the InkCanvas won't do anything with it. So:

    1. You need to create a single StrokeCollection
    2. You need to assume the contents of the collection will change, not the collection itself

    Example code:

    public class ViewModel : INotifyPropertyChanged
    {
        private readonly StrokeCollection _strokes;
    
        public ViewModel()
        {
            _strokes = new StrokeCollection();
            (_strokes as INotifyCollectionChanged).CollectionChanged += delegate
            {
                //the strokes have changed
            };
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        public StrokeCollection Signature
        {
            get
            {
                return _strokes;
            }
        }
    
        private void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
    
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
    

    And XAML:

    <InkCanvas Strokes="{Binding Signature}"/>