2011-01-28 4 views
4

탭 컨트롤을 확장하여 탭 항목을 닫을 수 있도록하고 싶습니다.Silverlight 4 : 닫기 가능한 Tabitem 만들기

나는 켄트의 WPF 솔루션을 발견 : On the WPF TabControl - can I add content next to the tab headers?

나는 혼합에서 기존의 실버 용을 TabControl의 사본을 열었다. 그러나 구조는 WPF tabcontrol과 상당히 다릅니다. Silverlight 컨트롤 템플릿으로 바로 가져올 수 없습니다.

나를위한 좋은 자료를 아는 사람이 있습니까?

답변

4

템플릿 탭을 사용하면 현재 선택된 탭을 닫기 위해 코드에서 연결할 수있는 일종의 닫기 버튼을 사용할 수 있습니다.

<Style TargetType="TabItem"> 
      <Setter.Value> 
       <ControlTemplate TargetType="sdk:TabItem"> 
          <Button x:Name="PART_btnClose" 
              Height="15" 
              Width="15" 
              Grid.Column="1" 
              HorizontalAlignment="Right" 
              VerticalAlignment="Center" 
              Margin="20,0,3,8" BorderThickness="1" Cursor="Hand" /> 
</ControlTemplate> 
</Setter.Value> 
</Style> 

이 후, 적용 템플릿에서 ButtonClicked 이벤트에 가입 할 수 있습니다. 이 같은

뭔가 : 해당 이벤트에

public override void OnApplyTemplate() 
    { 
     base.OnApplyTemplate(); 

     PART_btnClose = GetTemplateChild("PART_btnClose") as Button; 

     if (PART_btnClose != null) 
     { 
      PART_btnClose.Click += new RoutedEventHandler(PART_btnClose_Click); 
     } 

, 당신은 당신의 탭을 닫을 수 있습니다.

희망 이것은 도움이 될 수 있습니다. 코드가 그대로 작동하지 않을 수도 있습니다.

타이 Rozak

+0

답변 주셔서 감사합니다. 이것이 어떻게 효과가 있을지 조금 더 자세히 설명해 주시겠습니까? TabItem을 확장하는 TabItemExt 클래스를 만들면 OnApplyTemplate을 재정 의하여 말할 수 있습니다. 그러나 또한 TabControlExt 확장해야 TabControl 내부적으로 일반적인 TabItem 대신이 새 TabItemExt 활용할 것이다. 어떻게해야합니까?Many Thanks – Houman

+0

TabControl에 비헤이비어를 추가하지 않는 한 CustomTabControl이 필요하지 않습니다. 일반적으로 일반 TabItem을 추가 할 때 Xaml 또는 코드에 "CustomTabItem"을 추가하면됩니다. 이는 CustomTabItem이 TabItem에서 파생되어야하기 때문입니다. 추가 된 동작만으로 –

5

나는 이전과 같은 문제가 있었는데, 그때는 확장 TabControl을 사용하기로 결정했다. 나는 그것을 어디서 발견했는지 모르지만 그것은 중요하지 않습니다. 이제는 내 프로젝트에 있습니다.

이렇게하면 TabControl ViewModel 컬렉션에서 항목을 추가하거나 제거 할 수 있으며 변경 사항이 사용자 인터페이스에 반영됩니다.

MyTabControl.cs

public class MyTabControl : TabControl 
{ 
    public MyTabControl() 
     : base() 
    { 
     this.SelectionChanged += OnSelectionChanged; 
    } 

    #region Tabs with databinding and templates 
    /// <summary> 
    /// Template for a TabItem header 
    /// </summary> 
    public DataTemplate TabHeaderItemTemplate 
    { 
     get { return (DataTemplate)GetValue(TabHeaderItemTemplateProperty); } 
     set { SetValue(TabHeaderItemTemplateProperty, value); } 
    } 
    public static readonly DependencyProperty TabHeaderItemTemplateProperty = 
     DependencyProperty.Register("TabHeaderItemTemplate", typeof(DataTemplate), typeof(MyTabControl), new PropertyMetadata(
      (sender, e) => 
      { 
       ((MyTabControl)sender).InitTabs(); 
      })); 

    /// <summary> 
    /// Template for a content 
    /// </summary> 
    public DataTemplate TabItemTemplate 
    { 
     get { return (DataTemplate)GetValue(TabItemTemplateProperty); } 
     set { SetValue(TabItemTemplateProperty, value); } 
    } 
    public static readonly DependencyProperty TabItemTemplateProperty = 
     DependencyProperty.Register("TabItemTemplate", typeof(DataTemplate), typeof(MyTabControl), new PropertyMetadata(
      (sender, e) => 
      { 
       ((MyTabControl)sender).InitTabs(); 
      })); 

    /// <summary> 
    /// Source of clr-objects 
    /// </summary> 
    public IEnumerable MyItemsSource 
    { 
     get 
     { 
      return (IEnumerable)GetValue(MyItemsSourceProperty); 
     } 
     set 
     { 
      SetValue(MyItemsSourceProperty, value); 
     } 
    } 

    public static readonly DependencyProperty MyItemsSourceProperty = 
     DependencyProperty.Register("MyItemsSource", typeof(IEnumerable), typeof(MyTabControl), new PropertyMetadata(
      (sender, e) => 
      { 
       MyTabControl control = (MyTabControl)sender; 
       INotifyCollectionChanged incc = e.OldValue as INotifyCollectionChanged; 
       if (incc != null) 
       { 
        incc.CollectionChanged -= control.MyItemsSourceCollectionChanged; 
       } 
       control.InitTabs(); 

       incc = e.NewValue as INotifyCollectionChanged; 
       if (incc != null) 
       { 
        incc.CollectionChanged += control.MyItemsSourceCollectionChanged; 
       } 
      })); 


    /// <summary> 
    /// Selected item as object 
    /// </summary> 
    public object MySelectedItem 
    { 
     get { return (object)GetValue(MySelectedItemProperty); } 
     set { SetValue(MySelectedItemProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for MySelectedItem. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty MySelectedItemProperty = 
     DependencyProperty.Register("MySelectedItem", typeof(object), typeof(MyTabControl), new PropertyMetadata(
      (sender, e) => 
      { 
       MyTabControl control = (MyTabControl)sender; 

       if (e.NewValue == null) 
        control.SelectedItem = null; 
       else 
       { 
        var tab = control.Items.Cast<TabItem>().FirstOrDefault(ti => ti.DataContext == e.NewValue); 
        if (tab != null && control.SelectedItem != tab) 
         control.SelectedItem = tab; 
       } 
      })); 

    private void InitTabs() 
    { 
     Items.Clear(); 
     if (MyItemsSource != null && MyItemsSource.OfType<object>().Any()) 
     { 
      int i = 0; 
      foreach (var item in MyItemsSource) 
      { 
       var newitem = new TabItem(); 

       if (TabItemTemplate != null) 
        newitem.Content = TabItemTemplate.LoadContent(); 

       if (TabHeaderItemTemplate != null) 
        newitem.Header = TabHeaderItemTemplate.LoadContent(); 

       newitem.DataContext = item; 
       Items.Add(newitem); 
      } 
      VisualStateManager.GoToState(this, "Normal", true); 
     } 
     else VisualStateManager.GoToState(this, "NoTabs", true); 
    } 

    private void MyItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     if (e.Action == NotifyCollectionChangedAction.Add) 
     { 
      if (e.NewStartingIndex > -1) 
      { 
       foreach (var item in e.NewItems) 
       { 
        var newitem = new TabItem(); 

        if (TabItemTemplate != null) 
         newitem.Content = TabItemTemplate.LoadContent(); 

        if (TabHeaderItemTemplate != null) 
         newitem.Header = TabHeaderItemTemplate.LoadContent(); 

        newitem.DataContext = item; 
        Items.Add(newitem); 
       } 
      } 
     } 
     else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove) 
     { 
      if (e.OldStartingIndex > -1) 
      { 
       var ti = (TabItem)this.Items[e.OldStartingIndex]; 
       Items.RemoveAt(e.OldStartingIndex); 
      } 
     } 
     else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) 
     { 
      Items.RemoveAt(e.OldStartingIndex); 

      var newitem = new TabItem(); 

      if (TabItemTemplate != null) 
       newitem.Content = TabItemTemplate.LoadContent(); 

      if (TabHeaderItemTemplate != null) 
       newitem.Header = TabHeaderItemTemplate.LoadContent(); 

      newitem.DataContext = e.NewItems[0]; 

      Items.Add(newitem); 
      Items.Insert(e.NewStartingIndex, newitem); 
     } 
     else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Reset) 
     { 
      InitTabs(); 
     } 
    } 

    #endregion 

    private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     var si = e.AddedItems.Cast<TabItem>().FirstOrDefault(); 
     if (si != null) 
      this.MySelectedItem = si.DataContext; 
     else this.MySelectedItem = null; 
    } 
} 

에서 MainPage.xaml 속성이 MyItemsSourceMySelectedItem라는 것을

<my:MyTabControl MyItemsSource="{Binding Items}" MySelectedItem="{Binding SelectedITem}"> 
     <my:MyTabControl.TabHeaderItemTemplate> 
      <DataTemplate> 
       <Grid> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="*"/> 
         <ColumnDefinition Width="Auto"/> 
        </Grid.ColumnDefinitions> 
        <TextBlock Text="{Binding Title}" VerticalAlignment="Center"/> 
        <Button Content="X" Margin="3" Width="20" Height="20" Grid.Column="1" 
          Command="{Binding RequestCloseCommand}"/> 
       </Grid> 
      </DataTemplate> 
     </my:MyTabControl.TabHeaderItemTemplate> 
     <my:MyTabControl.TabItemTemplate> 
      <DataTemplate> 
       <ContentControl Content="{Binding Content}"/> 
      </DataTemplate> 
     </my:MyTabControl.TabItemTemplate> 
    </my:MyTabControl> 

공지 사항,이 TabControl 오브젝트를 사용하기 때문에,하지 TabItem.

그리고 두 ViewModels : MainViewModel.cs

public class MainViewModel 
{ 
    public MainViewModel() 
    { 
     this.Items = new ObservableCollection<TabItemViewModel> 
         { 
          new TabItemViewModel("Tab 1", OnItemRequestClose), 
          new TabItemViewModel("Tab item 2", OnItemRequestClose) 
         }; 
    } 

    public ObservableCollection<TabItemViewModel> Items { get; set; } 

    public void OnItemRequestClose(TabItemViewModel item) 
    { 
     this.Items.Remove(item); 
    } 
} 

TabItemViewModel.cs

public class TabItemViewModel 
{ 
    public TabItemViewModel(string title, Action<TabItemViewModel> onClose) 
    { 
     this.Title = title; 
     this.RequestCloseCommand = new DelegateCommand(_ => onClose(this)); 

     //Just a demontration 
     this.Content = "Test content "+title; 
    } 

    public string Title { get; set; } 

    public ICommand RequestCloseCommand { get; set; } 

    public object Content { get; set; }  
}