pmezykowski
pmezykowski

Reputation: 336

Caliburn.Micro ItemsSource is bound not to current viewmodel but to parent

I'm using Caliburn.Micro for WPF (using VS 2012 and targeting to .NET 4.5.1).

I have problem with binding itemsSource to ComboBox (but I investigate that in my case it happens also with other controls with ItemsSource property, like ListBox).

I have nested views (usercontrols) with viewmodels created with SimpleContainer (IoC).

Here is my problem:

Combobox is populated with items not from its view viewmodel (LanguageSelectionViewModel) but from parent view viewmodel (TopViewModel).

Also, when I removed items collection from parent viewmodel, my combobox was empty.

Code:

MainWindowView.xaml:

<Window
             mc:Ignorable="d"
             d:DesignHeight="300" 
             d:DesignWidth="300"
             d:DataContext="{d:DesignInstance d:Type=mainWindow:MainWindowViewModel}"
         >
    <Grid>
        <top:TopView 

            HorizontalAlignment="Stretch" 
            cal:Bind.Model="{Binding TopVM}" 
            />
          </Grid>
</Window>

MainWindowViewModel:

public class MainWindowViewModel : Screen
{
    private TopViewModel topVm;

    public TopViewModel TopVM
    {
        get { return topVm; }
        set
        {
            topVm = value;
            NotifyOfPropertyChange(() => TopVM);
        }
    }

    public MainWindowViewModel(TopViewModel topVm, ContentViewModel contentVm)
    {
        TopVM = topVm;
        TopVM.ConductWith(this);
    }
}

TopView.xaml:

<UserControl>
   <StackPanel Orientation="Horizontal">
      <languageSelection:LanguageSelectionView cal:Bind.Model="{Binding LanguageSelectionVM}"/>
   </StackPanel>
</UserControl>

TopViewModel.cs:

public class TopViewModel : Screen
{
    private LanguageSelectionViewModel _languageSelectionVM;

    public LanguageSelectionViewModel LanguageSelectionVM
    {
        get { return _languageSelectionVM; }
        set
        {
            _languageSelectionVM = value;
            NotifyOfPropertyChange(() => LanguageSelectionVM);
        }
    }

    public TopViewModel(ClockViewModel clockVm, LanguageSelectionViewModel languageSelectionVM)
    {
        this.Items = new ObservableCollection<string>() { "a", "a", "a" };

        LanguageSelectionVM = languageSelectionVM;
        LanguageSelectionVM.ConductWith(this);
    }

    private ObservableCollection<string> _items;

    public ObservableCollection<string> Items
    {
        get { return _items; }
        set
        {
            _items = value;
            NotifyOfPropertyChange(() => Items);
        }
    }

}

LanguageSelectionView.xaml:

<UserControl>
    <StackPanel Orientation="Vertical">
        <ComboBox ItemsSource="{Binding Items}"/>
    </StackPanel>
</UserControl>

LanguageSelectionViewModel.cs:

public class LanguageSelectionViewModel : Screen
{
    private ObservableCollection<string> _items;

    public ObservableCollection<string> Items
    {
        get { return _items; }
        set
        {
            _items = value;
            NotifyOfPropertyChange(() => Items);
        }
    }

    public LanguageSelectionViewModel()
    {
        this.Items = new ObservableCollection<string>() { "1", "a" };
    }
}

I had also tried to populate this collection later, with no success:

    protected override void OnViewReady(object view)
    {
        base.OnViewReady(view);
        this.Items = new ObservableCollection<string>() { "1", "a" };
        Refresh();
    }

DataContext seems to be okay, because binding to textbox

<TextBlock Text="{Binding TestString}"/>

works fine.

Upvotes: 2

Views: 1046

Answers (2)

pmezykowski
pmezykowski

Reputation: 336

Ok, mystery solved.

Instead of nesting controls like this:

  <Grid>
     <top:TopView 
        cal:Bind.Model="{Binding TopVM}" />
  </Grid>

I should write:

  <Grid>
     <ContentControl
        cal:View.Model="{Binding TopVM}" />
  </Grid>

And there is no need to force DataContext.

Upvotes: 1

pmezykowski
pmezykowski

Reputation: 336

I figure out that ComboBox whas the only control that had DataContext set to parent View Model, not to proper View model.

It works by forcing it in this way:

<ComboBox 
         DataContext="{Binding}"
         ItemsSource="{Binding Items}" >

But still is the question - why? This is bug or feature of Caliburn.Micro?

Upvotes: 0

Related Questions