views:

66

answers:

1

We're using Caliburn.Micro/Silverlight 4 and life is good.

I'm trying to bind a combobox's itemsSource to a viewModel, but this doesn't seem possible since the combobox is already bound to its own row's dataItem. The logic which fills the combo changes with other data on the screen so I can't really use a static list like I've been using.

Is there a way to bind directory to the viewModel somehow??? I've tried element to element binding but this never appears to work within the grid.

       <Controls:DataGridTemplateColumn x:Name="FooNameCol" Header="Foo" MinWidth="200">
            <Controls:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>

                    <StackPanel>
                        <TextBlock Text="{Binding Path=Foo.ShortName}" 
                                   Style="{StaticResource DataGridTextColumnStyle}"/>
                    </StackPanel>

                </DataTemplate>
            </Controls:DataGridTemplateColumn.CellTemplate>
            <Controls:DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>

                    <ComboBox DisplayMemberPath="ShortName"   
                              MinWidth="200" MinHeight="25"
                              SelectedItem="{Binding Path=Officer, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
                              ItemsSource="{Binding Officers, Source={StaticResource ReferenceListRetriever}}" />

                </DataTemplate>
            </Controls:DataGridTemplateColumn.CellEditingTemplate>
        </Controls:DataGridTemplateColumn>
A: 

Within a DataTemplate, the DataContext is bound to each single item of the corresponding list; since all Bindings implicitly refers to DataContext, you have to ensure that the path is valid, starting from the single data item.

In your scenario, for the indicated binding to work, you should have a VM shaped this way:

public class MyVM {
   public IEnumerable<MyItem> Items {get;}
}

public class MyItem {
  public Foo Foo {get;}
  public Officer Officer {get;set;}
  public IEnumerable<Officer> Officers {get;}
}

It may seem an overkill, but in some scenarios each combo can actually contain different choices for each data item, based on some business rule. In simpler cases MyItem can just expose a common list coming from the parent MyVM:

public class MyItem {
  ...
  public IEnumerable<Officer> Officers {
    get { return _parent.AvailableOfficers; }
  }
}

If you really can't live with it and prefer to keep the available Officers list in the root VM only, you can use a Xaml side trick:

public class MyVM {
  public IEnumerable<MyItem> Items {get;}
  public IEnumerable<Officer> Officers {get;}
}

public class MyItem {
  public Foo Foo {get;}
  public Officer Officer {get;set;}
}

Xaml:

<UserControl ...>
  ...
  <AnyFrameworkElementAtThisLevel Name="bridge" />
  ...
  <Controls:WhateverGrid>
     ...
     <Controls:DataGridTemplateColumn ...>
        <Controls:DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
              ...
            </DataTemplate>
        </Controls:DataGridTemplateColumn.CellTemplate>
        <Controls:DataGridTemplateColumn.CellEditingTemplate>
            <DataTemplate>
                <ComboBox DisplayMemberPath="ShortName"   
                          SelectedItem="{Binding Path=Officer, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
                          ItemsSource="{Binding DataContext.Officers, ElementName=bridge}" />

            </DataTemplate>
Marco Amendola