1
votes

I have a TabControl with an ItemsSource of multiple TabItems, and an additional TabItem that adds new TabItems to this list. The TabItem responsible for adding an item listens to the MouseUp event. The problem is, that after adding an item I update the SelectedIndex, but then the SelectedIndex changes to the element I've clicked on.

Part of the XAML:

<TabControl ItemsSource="{Binding Tabs}" SelectedIndex="{Binding SelectedIndex}">

My code:

public ObservableCollection<TabItem> Tabs { get; set; }
public int SelectedIndex { get; set; }

private void Tab_add_MouseUp(object sender, MouseButtonEventArgs e)
{
    e.Handled = true;
    int count = Tabs.Count;
    TabItem tabItem = new TabItemDepartment("Header #x");
    Tabs.Insert(count - 1, tabItem);
    SelectedIndex = count - 2;
}

edit: Final code (only relevant parts) based on answers:

public class CalendarViewModel : INotifyPropertyChanged
{
    public ObservableCollection<TabItem> Tabs { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    private int _SelectedIndex;
    public int SelectedIndex
    {
        get
        {
            return _SelectedIndex;
        }
        set
        {
            _SelectedIndex = value;
            NotifyPropertyChanged(nameof(SelectedIndex));
        }
    }

    private void Tab_add_MouseDown(object sender, MouseButtonEventArgs e)
    {
        TabItem tabItem = new TabItemDepartment("Header #x");
        Tabs.Insert(Tabs.Count - 1, tabItem);
        SelectedIndex = Tabs.Count - 2;
        e.Handled = true;
    }

    protected void NotifyPropertyChanged(string propertyName = null)
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
2
Try doing it in preview mousedown event, if e.Handled stops the event from routing down, then it should work.Jai
That works, but it doesn't change the SelectedIndex. So the index stays the same when I click on the add tab.Johannes

2 Answers

2
votes

You need to use either DependencyProperty, or INotifyPropertyChanged, because the binding engine is not aware of the changes of SelectedIndex property.

public static readonly DependencyProperty SelectedIndexProperty = DependencyProperty.Register(
    "SelectedIndex",
    typeof(int),
    typeof(WhateverYourClassNameIs));

public int SelectedIndex
{
    get { return (int)GetValue(SelectedIndexProperty); }
    set { SetValue(SelectedIndexProperty, value); }
}

Alternatively, you can make this class implement INotifyPropertyChanged, but generally for classes that already derive from FrameworkElement (classes with UI), DependencyProperty would be preferred.

1
votes

You have 2 issues here:

  1. SelectedIndex does need to either be a DependencyProperty or your class with SelectedIndex defined needs to implement INotifyPropertyChanged.

Try this:

public int SelectedIndex
{
    get { return (int)GetValue(SelectedIndexProperty); }
    set { SetValue(SelectedIndexProperty, value); }
}

public static readonly DependencyProperty SelectedIndexProperty =
    DependencyProperty.Register("SelectedIndex", typeof(int), typeof(YOURCLASS), new PropertyMetadata(0));
  1. Your logic in the mouse up event is wrong. I assume you only want to add a tab if the last item is clicked? Also you cannot use your local count variable because the number of items in the collection changes once you add your new tab.

Try this:

private void Tab_add_MouseUp(object sender, MouseButtonEventArgs e)
{
    e.Handled = true;
    // Only add if the user clicks on the last items.
    if (this.SelectedIndex == this.Tabs.Count - 1)
    {
        TabItem tabItem = new TabItemDepartment("Header #x");
        this.Tabs.Insert(this.Tabs.Count - 1, tabItem);
        // The Count has changed at this point so make sure we check the collection again.
        this.SelectedIndex = this.Tabs.Count - 2;
    }
}