2015-08-13 3 views
2

У меня есть TabControl так:МОФА как переключить родительскую вкладку с вложенного зрения

<TabControl> 
    <local:TabItem x:Name="son" Header="son"> 
     <local_son:SonView /> 
    </local:TabItem> 
    <local:TabItem x:Name="daughter" Header="daughter"> 
     <local_daughter:DaughterView /> 
    </local:TabItem> 
</TabControl> 

Существует кнопка в DaughterView, я хочу, чтобы нажать на эту кнопку, чтобы переключиться на вкладки сына. Мои вопросы: как я могу добраться до tabindex вкладки son в DaughterView?

Спасибо заранее!

ответ

0

Кажется, странно иметь кнопку внутри переключателя табуляции на другой вкладке. Я бы подумал, что это будет панель инструментов или что-то в этом роде. То есть вне вкладки. Но если вы настаиваете:) ... Я бы использовал шаблон агрегатора мессенджера/события и опубликовал событие и подписал вид и переключил вкладку. У меня не было бы такого взгляда на ребенка.

0

Вам необходимо привязать «SelectedIndex» к собственности в вашей модели. Я лично, как держать вещи типа безопасным и в состоянии быть блок-тестирования, поэтому, когда мне нужно манипулировать TabControls в коде я обычно начинаю объявить перечисление с одним значением для каждой вкладки:

public enum MyTabs : int 
{ 
    [Description("Tab 1")] 
    Tab1, 

    [Description("Tab 2")] 
    Tab2, 

    [Description("Tab 3")] 
    Tab3 
} 

Атрибут Описание является текст, который я хочу отобразить в заголовке вкладки, подробнее об этом в одно мгновение. На моем взгляде модель содержит член MyTabs типа, который обновляется каждый раз, когда пользователь нажимает на вкладку, и которую я могу также установить вручную сам с помощью кода:

public class MyViewModel : ViewModelBase 
{ 
    private MyTabs _CurrentTab; 
    public MyTabs CurrentTab 
    { 
     get { return this._CurrentTab;} 
     set { this._CurrentTab = value; RaisePropertyChanged(() => this.CurrentTab); } 
    }  
} 

Теперь вам нужно связать свой TabControl этого свойства:

<TabControl 
    ItemsSource="{Binding Source={StaticResource MyTabs}}" 
    SelectedIndex="{Binding CurrentTab, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, Converter={StaticResource EnumToIntConverter}}"> 
    <TabControl.Resources> 
     <Style TargetType="{x:Type TabItem}"> 
      <Setter Property="Header" Value="{Binding Path=., Converter={StaticResource EnumDescriptionConverter}}" /> 
     </Style> 
    </TabControl.Resources> 
</TabControl> 

к сожалению WPF привязка не достаточно умна, чтобы работать с целыми перечислениями, поэтому я также использую конвертер, чтобы бросить между перечислениями и целыми числами:

public class EnumToIntConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return (int)value; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return Enum.ToObject(targetType, value); 
    } 
} 

есть несколько других вещей, происходящих здесь ... прежде всего вы заметите, что я вообще не объявляю TabItems. Это потому, что я генерирую их автоматически из значений Enum; если я добавлю новое значение в перечисление MyTab, тогда появится волшебная вкладка! В этом случае я привязка к статическому ресурсу с ключом «MyTabs», это ObjectDataProvider, которая перечисляет значения в моем перечислении:

<ObjectDataProvider x:Key="MyTabs" MethodName="GetValues" ObjectType="{x:Type sys:Enum}"> 
     <ObjectDataProvider.MethodParameters> 
      <x:Type TypeName="local:MyTabs"/> 
     </ObjectDataProvider.MethodParameters> 
    </ObjectDataProvider> 

Это поднимает вопрос о том, как язычки знают, что отображать в их заголовков и областей содержимого tabitem. В заголовках используется атрибут «Описание», объявленный в перечислении, код для EnumDescriptionConverter находится на another page on this site. Чтобы указать контент для каждой страницы, я создаю ControlTemplate для каждого из моих значений перечисления и нажимаю его на значение enum. Шаблон данные затем используется для выбора подходящей для использования для каждой вкладки:

<Window.Resources> 

    <ControlTemplate x:Key="{x:Static local:MyTabs.Tab1}"> 
     <TextBlock Text="This is the first tab" /> 
    </ControlTemplate> 

    <ControlTemplate x:Key="{x:Static local:MyTabs.Tab2}"> 
     <TextBlock Text="This is the second tab" /> 
    </ControlTemplate> 

    <ControlTemplate x:Key="{x:Static local:MyTabs.Tab3}"> 
     <TextBlock Text="This is the third tab" /> 
    </ControlTemplate> 

    <DataTemplate DataType="{x:Type local:MyTabs}"> 
     <ContentControl> 
      <ContentControl.Template> 
       <MultiBinding Converter="{StaticResource ResourceKey=BindingToResourceConverter}"> 
        <Binding RelativeSource="{RelativeSource AncestorType={x:Type Window}}" Path="Resources" /> 
        <Binding />  
       </MultiBinding> 
       </ContentControl.Template> 
      </ContentControl> 
     </DataTemplate> 

</Window.Resources> 

Заключительная частью головоломки является BindingToResourceConverter, который просто принимает привязку (то есть одно из значений перечислений) и использует его найдите соответствующий контрольный образец:

public class BindingToResourceConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return (values[0] as ResourceDictionary)[values[1]]; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

И все! Каждый раз, когда я хочу добавить новую страницу в TabControl, я просто добавляю значение в соответствующее перечисление и создаю ключ ContentControl к этому значению. Все остальное происходит автоматически, и лучше всего это как безопасно, так и выборочно.

+0

Не было совершено преступления, но я не понимаю вашу реализацию здесь.Это действительно бессмысленно. Вы просто закодировали 3 вкладки, но перенесли часть «жесткого кодирования» представления (XAML) на виртуальную машину. Вы уже привязаны к коллекции, было бы намного проще сделать заголовок собственностью коллекции. Вы также создаете необходимость в наборе ненужных шаблонов, вы запрещаете редактирование пользовательского интерфейса в порядке вкладок/вкладок с момента его жесткого кодирования, и вы также можете разбить локализацию XAML, если вам это нужно. И, конечно же, вы не можете добавлять/удалять вкладки во время выполнения с этим. – SledgeHammer

+0

Без обид! :) Да, перемещение XAML в виртуальную машину на самом деле является целым пунктом упражнения, поскольку оно облегчает модульное тестирование, например. действительно ли нажатие на кнопку вызывает активацию соответствующей вкладки? В этом конкретном примере перечислялось перечисление для создания вкладок, но я использую шаблоны данных, поэтому вам нечего останавливать на использовании ObservableCollection, содержащих эти перечисления (в штучной упаковке) и других типов данных, что также решает проблему добавления и удаления вкладок. Полностью согласен с вашей локализацией, на самом деле я не использую атрибут Description, но я хотел, чтобы все было просто. :) –

Смежные вопросы