4

タブコントロールを拡張して、閉じることができるタブアイテムを作成したいと思います。

KentのこのWPFソリューションを見つけました: WPF TabControlで-タブヘッダーの横にコンテンツを追加できますか?

Blendで既存のSilverlightタブコントロールのコピーを開きました。ただし、構造はWPFタブコントロールとはかなり異なります。Silverlightコントロールテンプレートに正しく取り込むことができません。

誰かが私にとって良いリソースを知っていますか?

4

2 に答える 2

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

<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> 

プロパティはとと呼ばれることに注意してくださいMyItemsSourceMySelectedItemこれTabControlは、ではなくオブジェクトを使用するためTabItemです。

そして2つの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; }      
}
于 2011-01-28T16:02:53.113 に答える
4

TabItemをテンプレート化して、現在選択されているタブを閉じるためにコードビハインドに接続できるある種の閉じるボタンを設定できます。

<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);
        }

その場合は、タブを閉じることができます。

これがお役に立てば幸いです。コードがそのまま機能しない可能性があります。

Ty Rozak

于 2011-01-28T15:53:21.223 に答える