3
votes

Setup: I have a tabcontrol with 0...n tabs, and each tab is bound to a class:

class MyTabItem
{
    string Text {get; set;}
    int ID {get; set;}
    ISet<MyTabContent> Contents {get; set;}
}

Class MyTabContent
{
    int ID {get; set;}
    string Subtext {get; set;}
}

Each tabitem class has many tabcontent classes in it's set. (The whole thing gets fetched via NHibernate).

I've tried a lot of things to bind the content of MyTabItem to the header of each tabcontrol item, and the content of MyTabContent to a datagrid in the content of each tabcontrol item.

I can display all the content in the tabs, but whenever I change properties in the bound classes, the UI does not update. I've tried to call InvalidateVisual, tried to Dispatch a Render event, tried to UpdateTarget and UpdateSource on the bindings (those last 2 threw exceptions). I've implemented INotifyPropertyChanged in my viewmodel, and even tried manually using OnPropertyChanged("MyTabItem") to no avail.

I really don't understand why my tabcontrol contents won't update when I change properties in the bound classes. I've tried 2 different binding strategies, either works in displaying the content, but neither updates when the content changes.

My XAML setup is:

<TabControl>
  <TabControl.ItemTemplate>
    <DataTemplate DataType="models:MyTabItem">
      <TextBlock Text="{Binding Text}" />
    </DataTemplate>
  </TabControl.ItemTemplate>
  <TabControl.ContentTemplate>
    <DataTemplate DataType="models:MyTabItem">
      <DataGrid ItemsSource="{Binding Contents}">
        <DataGrid.Columns>
          <DataGridTextColumn Binding="{Binding Path=Subtext}" />
        </DataGrid.Columns>
      </DataGrid>
    </DataTemplate>
  </TabControl.ContentTemplate>
</TabControl>

With that XAML setup, I simply added Items to the tabcontrol with tabcontrol.Items.Add(new MyTabItem).

Then I tried another XAML setup where I bound the tabcontrol.Itemsource to an ObservableCollection in the code-behind. Again, the tab content did not update if the bound properties change :(

I also tried making a CurrentItem property in the ViewModel, and used that as a Window.Resource, and then bound the Tabcontrol contents to

{Binding Source={StaticResource CurrentItem}, Path=Text}

And whenever I changed tabs I would update the CurrentItem in the viewmodel, but with that it also didn't update changes.

I'm pretty much out of ideas :(

1
Is that the actual code of your ViewModels? WPF doesn't support binding to Fields, only properties.Federico Berasategui
They are properties in my viewmodel, I just forgot to insert the setters and getters into my pseudocode. Updated it in the question.Aether McLoud

1 Answers

4
votes

You need to implement INotifyPropertyChanged

Keep in mind there's a new attribute in .NET 4.5 that simplifies the task, take a look here

Here's a sample, apply that to both your classes, the list will need to become ObservableCollection:

private ObservableCollection<MyTabContent> _contents = new  ObservableCollection<MyTabContent>();
public ObservableCollection<MyTabContent> Contents { get { return _contents; } }

-

public class MyTabContent : INotifyPropertyChanged
{
    private int _id;
    int ID {
        get{ return _id; }
        set{ _id = value; OnPropertyChanged(); }
    }

    private string _subText;
    public string Subtext {
        get{ return _subText; }
        set{ _subText= value; OnPropertyChanged(); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    { 
        if (PropertyChanged!= null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}