views:

773

answers:

4

hello i'm building a wpf app with data grids, the pattern is model view view model.

all og my screens contains a contentcontrol, and i just assign him the view model, that have a suitable data template,

anyway, my problem is with combo box column, the data context is the presented entity, and i need it to be the view model.

whats the best solution?

A: 

I'm using another datagrid, but it might be similar. The way i did it was like that:

in the XAML, i defined an ObjectDataProvider in the resources:

<ObjectDataProvider x:Key="VM" ObjectInstance="{x:Null}" x:Name="vm"/>

then after assigning the DataContext (either the constructor or the DataContextChanged event), i did this:

(this.Resources["VM"] as ObjectDataProvider).ObjectInstance = this.DataContext;

In the Combobox xaml, i used that as binding source:

ItemsSource="{Binding Source={StaticResource VM}, Path=SomeItems, Mode=OneWay}"

Not sure if it works for the microsoft datagrid, but i guess it's worth a try.

Botz3000
xceed express grid?
abmv
Yes. As far as i know, for both the items are not directly part of the visual tree, so something like this might do it.
Botz3000
A: 

Hi, this is how I used ViewModel with ComboBoxes, the DataContext is the ViewModel, not the underlying entity (List<Person>).

ViewModel (Person is a Simple class with Name and Age):

public class PeopleViewModel : INotifyPropertyChanged
{
    private List<Person> _peopleList;
    private Person _selectedPerson;

    public PeopleViewModel()
    {
  // initialize with sample data
  _peopleList = getPeopleList();
    }

    // gets sample data
    private List<Person> getPeopleList()
    {
        var result = new List<Person>();
        for (int i = 0; i < 10; i++)
        {
            result.Add(new Person("person " + i, i));
        }
        return result;
    }

 public List<Person> PeopleList
    {
  get { return _peopleList; }
    }

    public Person SelectedPerson
    {
        get { return _selectedPerson; }
        set
        {
            if (_selectedPerson == value) return;
            _selectedPerson = value;
            // required so that View know about changes
            OnPropertyChanged("SelectedPerson");
        }
    }
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    // WPF will listen on this event for changes
    public event PropertyChangedEventHandler PropertyChanged;
}

XAML for ComboBox:

<ComboBox Name="cmbEnum" Width="150" ItemsSource="{Binding Path=PeopleList}" SelectedValue="{Binding Path=SelectedPerson}" SelectedValuePath="" DisplayMemberPath="Name" ></ComboBox>

And in code behind I can do:

    public Window2()
    {
        InitializeComponent();

        vm = new PeopleViewModel();
        // we are listening on changes of ViewModel, not ComboBox
        vm.PropertyChanged += new PropertyChangedEventHandler(vm_PropertyChanged);
        this.DataContext = vm;
    }

    void vm_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
 if (e.PropertyName == "SelectedPerson")
 {
  MessageBox.Show(vm.SelectedPerson.Age.ToString());
 }
    }

    // button1_Click should be probably replaced by Command
    private void button1_Click(object sender, RoutedEventArgs e)
    {
        // sample showing that GUI is updated when ViewModel changes
 vm.SelectedPerson = vm.PeopleList[2];
    }

Hope this helps, I'm quite new to WPF, I'd like to hear any feedback if this is the right way to use MVVM, I think it's quite elegant since you only deal with the ViewModel and Model in code, and the View can be replaced.

Martin Konicek
A: 

I Found that the best way of implementing this is define some external class for all lookups that i use in grid and embedd them in the template as a static resource

Chen Kinnrot
A: 

We ended up having classes with static properties for each of of our combo box lists:

(you can't make the class itself static otherwise XAML won't be able to open it, but you won't get compile errors)

For example:

public class ZoneList
{
  private static readonly IList<Zone> _Items = new List<Zone>();
  public static IList<Zone> Items
  {
    get { return _Items; }
  }
}

and then in XAML:

<UserControl.Resources>
    <ResourceDictionary>
     <ObjectDataProvider x:Key="myZoneList"   ObjectType="{x:Type StaticLists:ZoneList}"/>
    </ResourceDictionary>
</UserControl.Resources>

<ComboBox ItemsSource="{Binding Path=Items, Source={StaticResource myZoneList}}"></ComboBox>
John Weldon