views:

49

answers:

1

Hi.
Im currently trying to get my first WPF Usercontrol to work. It consists of some UI elements and a ViewModel, holding the data and doing the work. It has a List of items as input, and another List of items as output. I need a certain task in my ViewModel to be done, when the list bound to the input changes. But i can't find a way to run a method at change of this List.

I thought the best way is to have 2 DependencyProperties for the input and output list. If the output list changes, the bound objects should be informed as it is registered as DependencyProperty. And i wanted to use the DependencyPropertyChanged delegate to specify the method in my ViewModel to execute on Input change.

public List<AClass> Input
    {
        get { return (List<AClass>)GetValue(InputProperty); }
        set { SetValue(InputProperty, value); }
    }
public static readonly DependencyProperty InputProperty =
        DependencyProperty.Register("Input", typeof(List<AClass>), typeof(MyUserControl), new UIPropertyMetadata(new List<AClass>(),CallBackDelegate));

I tried different approaches to set the delegate in the viewmodel constructor, but they all did not work. How can I specify a method within my viewmodel to execute on change of input List?

+1  A: 

Instead of lists in a DependencyProperty, I would use ObservableCollections. That gives you "automatic" notifications, etc. Here is outta-my-head-probably-not-quite-complete pseudo code to get you started:

ViewModel

using System.Collections.ObjectModel;

namespace MyNamespace;

class MyViewModel
{
    ObservableCollection<AClass> mInput = new ObservableCollection<AClass>();
    ObservableCollection<AClass> mOutput = new ObservableCollection<AClass>();

    public MyViewModel()
    {
        mInput.CollectionChanged += 
            new NotifyCollectionChangedEventHandler(mInput_CollectionChanged);
    }

    void mInput_CollectionChanged(object sender, 
                                  NotifyCollectionChangedEventArgs e)
    {
        DoSomething();    
    }

    public ObservableCollection<AClass> Input
    {
        get { return mInput; }
    }

    public ObservableCollection<AClass> Output
    {
        get { return mOutput; }
    }
}

Somewhere in Control/View

<ItemsControl ItemsSource="{Binding Input}">
    <!-- Rest of control design goes here -->
</ItemsControl>

<ItemsControl ItemsSource="{Binding Output}">
    <!-- Rest of control design goes here -->
</ItemsControl>

Control/View Code-Behind

class MyViewOrControl
{
    // ViewModel member
    private readonly MyViewModel mViewModel = new MyViewModel();

    // Constructor
    public MyViewOrControl()
    {
        InitializeComponent();
        this.DataContext = mViewModel;
    }

    // Property (if needed)
    public ViewModel
    {
        get { return mViewModel; }
    }
}
Wonko the Sane
Thanks, thats more elegant than my solution. But in your solution the tables are only in the viewmodel, causing a lot of warnings and even errors in the XAML like 'property not found' or 'no definition for'.Any tips?
Marks
Sorry - have been on vacation and off the grid for a few days... It's a little difficult to know what the problem is without seeing your code, but my example assumes that you set the DataContext of your View (control) to be the ViewModel. I am updating the answer to show one way to do that. If that does not solve the problem, please provide more details.
Wonko the Sane