Вопрос по wpf, c#, tabcontrol, mvvm – Получение родителя новой вкладки после добавления в связанный TabControl (mvvm)

2

Я добавляю кнопку закрытия на мои вкладки, используя следующее руководство:

http://www.codeproject.com/Articles/84213/How-to-add-a-Close-button-to-a-WPF-TabItem

Это стало проблемой, потому что событие использует «родитель» добавленной вкладки, чтобы удалить эту вкладку из tabcontrol. Я связываю элемент управления tab с помощью mvvm, поэтому свойство parent, по-видимому, не устанавливается и дает мне исключение нулевой ссылки для родителя, когда событие пытается удалить из него.

Вот привязка, чтобы вы поняли:

<TabControl Name="tabControl" Margin="0,22,0.2,-5.2" ItemsSource="{Binding Tabs}" Background="#FF4C76B2"/>

Вот где вкладки добавляются.

private void AddTab(object tabName)
{
    ClosableTab newTab = new ClosableTab();
    newTab.Title = "title?";
    //newTab.Header = tabName;
    TextBox test = new TextBox();

    test.Text = "CONTENT (" + tabName + ") GOES HERE";
    newTab.Content = test;

    Tabs.Add(newTab);
    OnPropertyChanged("Tabs");
}

Вот событие, где происходит нулевая ссылка:

void button_close_Click(object sender, RoutedEventArgs e)
{
    ((TabControl)this.Parent).Items.Remove(this);
}

На мой взгляд, есть два варианта:

попробуйте найти другой способ удалить вкладку (без родительского свойства)попытаться найти способ как-то установить родительское свойство (что не может быть сделано напрямую, оно выдает ошибку компилятора)

Ваш Ответ

1   ответ
2

данныенеЭлементы пользовательского интерфейса, Мы работаем с коллекциями классов, которые содержат все свойства, необходимые для выполнения некоторых требований, и данные связывают эти свойства с элементами управления пользовательского интерфейса вDataTemplates. Таким образом, мы добавляем элементы управления UI, добавляя элементы данных в эти коллекции, и позволяем замечательной системе шаблонов WPF позаботиться об UI.

Например, у вас естьTabControl что мы хотим добавить или удалитьTabItemс ... в надлежащем MVVM пути. Во-первых, нам нужна коллекция предметов, которые могут представлять каждыйTabItem:

public static DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof(ObservableCollection<string>), typeof(TestView));

public ObservableCollection<string> Items
{
    get { return (ObservableCollection<string>)GetValue(ItemsProperty); }
    set { SetValue(ItemsProperty, value); }
}

Я просто используюDependencyProperty потому что я выбил это вUserControl и я просто использую коллекциюstringдля простоты. Вам нужно создать класс, который содержитвсе данных, необходимых для всегоTabItem содержание. Далее, давайте посмотримTabControl:

<TabControl ItemsSource="{Binding Items}" ItemTemplate="{StaticResource ItemTemplate}" />

Мы данные связываем коллекцию сTabControl.ItemsSource свойство и мы устанавливаемTabControl.ItemTemplate кResource названныйItemTemplate, Давайте посмотрим, что сейчас:

xmlns:System="clr-namespace:System;assembly=mscorlib"
...
<DataTemplate x:Key="ItemTemplate" DataType="{x:Type System:String}">
    <TabItem Header="{Binding}" />
</DataTemplate>

ЭтотDataTemplate определяет, как будет выглядеть каждый элемент в нашей коллекции. Для простоты нашstringэто просто данные, связанные сTabItem.Header свойство. Это означает, что для каждого элемента, который мы добавляем в коллекцию, мы получим новыйTabItem с этимиHeader свойство установлено в значениеstring:

Items.Add("Tab 1");
Items.Add("Tab 2");
Items.Add("Tab 3");

Обратите внимание, что я включилSystem Префикс пространства имен XML для полноты, но вам это не нужно, потому что вашDataType будет вашим собственным классом. Вам нужно большеDataTemplateс тоже. Например, если ваш пользовательский класс имелHeader собственность иContent свойство, которое было другим пользовательским классом, скажем, называетсяContent, который содержал все свойства дляTabItem.Content собственности, вы можете сделать это:

<DataTemplate x:Key="ItemTemplate" DataType="{x:Type YourPrefix:YourClass}">
    <TabItem Header="{Binding Header}" Content="{Binding Content}" />
</DataTemplate> 
<DataTemplate DataType="{x:Type YourPrefix:Content}">
    <YourPrefix:SomeUserControl DataContext="{Binding}" />
</DataTemplate>

Так что это даст вамTabItemсHeaderустановлен иContent это исходит отSomeUserControl который вы могли бы разработать. Вам не нужно использоватьUserControls, вы можете просто добавить больше элементов управленияDataTemplate, Но вам нужно будет добавить куда-нибудь больше элементов управления ... и больше классов и свойств, всегда помня о правильной реализации основныхINotifyPropertyChanged интерфейс.

И, наконец, чтобы ответить на ваш вопрос надлежащим образом MVVM ... чтобы удалитьTabItem, вы просто удаляете элемент, который относится к этомуTabItem из коллекции. Просто ... или было бы, если бы вы действительно использовали MVVM, как вы утверждаете. Это действительно стоит изучить MVVM правильно, так как вы скоро увидите преимущества. Я оставлю вас, чтобы найти ваши собственные учебники, так как есть из чего выбирать.

ОБНОВЛЕНИЕ >>>

Ваша обработка событий все еще не так MVVM ... вам не нужно нигде передавать ссылку на любую модель представления. Путь MVVM заключается в использовании команд в модели представления. В частности, вы должны исследоватьRelayCommand, У меня есть своя версия, но эти команды позволяют нам выполнять действия с привязкой к даннымButtons и другие элементы управления пользовательского интерфейса, используя методы или встроенныеdelegateS в виде модели (гдеaction а такжеcanExecute в этом примереCommandParameter ценности):

<Button Content="Close Tab" Command="{Binding CloseTabCommand}" 
    CommandParameter="{Binding}" />

...

public ICommand CloseTabCommand
{
    get { return new ActionCommand(action => Items.Remove(action), 
        canExecute => canExecute != null && Items.Contains(canExecute)); }
}

Так что независимо от модели представленияTabs коллекция должна иметьAddTabCommand иCloseTabCommand которые добавляют и удаляют элементы изTabs коллекция. Но чтобы было ясно, чтобы это работало правильно, вашClosableTab класс должен быть классом данных, а не классом управления пользовательским интерфейсом. ИспользоватьDataTemplate указать его, если это элемент управления пользовательского интерфейса.

Вы можете узнать оRelayCommand изэта статья на MSDN.

Коллекция Observable, которую я связал itemsSource, - это 'Tabs' в приведенном выше коде. Что касается простого удаления из коллекции, да, именно это я и сделал (хотя мне не нравится, что мне пришлось передать ссылку на мою модель представления, чтобы получить из нее свойство Tabs) rcj

Похожие вопросы