Silverlight 4: создание табличных таблиц - PullRequest
4 голосов
/ 28 января 2011

Я хотел бы расширить элемент управления вкладками, чтобы иметь закрываемые элементы вкладки.

Я нашел это решение WPF Кента: На WPF TabControl - можно ли добавить контент рядом с заголовками вкладок?

Я открыл копию существующего Silverlight Tabcontrol в Blend. Однако структура выглядит совсем иначе, чем вкладка WPF. Я не могу получить это прямо в шаблон управления Silverlight.

Кто-нибудь знает хороший ресурс для меня?

Ответы [ 2 ]

5 голосов
/ 28 января 2011

У меня раньше была такая же проблема, и затем я решил использовать расширенный 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> 

Обратите внимание, что свойства называются MyItemsSource и MySelectedItem, поскольку в этом TabControl используются объекты, а не TabItem.

и две модели представления: 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; }      
}
4 голосов
/ 28 января 2011

У шаблона 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);
        }

В этом случае вы можете закрыть вкладку.

Надеюсь, что это помогает, код может не работать как есть, простосделал это быстро.

Тай Розак ​​

...