WPF TabItem Custom ContentTemplate

Некоторое время я боролся с этим, это было бы просто сделать в WindowForms.

Я делаю IRC-клиент, там будет несколько вкладок, по одной для каждого канала, к которому подключается. Каждая вкладка должна отображать ряд вещей: UserList, MessageHistory, Topic.

В WindowForms я бы просто унаследовал от TabItem, добавил бы некоторые настраиваемые свойства и элементы управления и готово.

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

Я пробовал много способов сделать это, и ниже представлен мой текущий метод, но я не могу заставить TextBox привязаться к свойству темы.

    <Style TargetType="{x:Type t:IRCTabItem}" BasedOn="{StaticResource {x:Type TabItem}}" >
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="540" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <StackPanel Grid.Column="0">
                        <TextBox Text="{Binding Topic, RelativeSource={RelativeSource AncestorType={x:Type t:IRCTabItem}}}" />   
                    </StackPanel>
                </Grid>
            </DataTemplate>              
        </Setter.Value>
    </Setter>
</Style>

И код позади

 public class IRCTabItem : TabItem
    {
        static IRCTabItem()
        {
            //This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
            //This style is defined in themes\generic.xaml
            //DefaultStyleKeyProperty.OverrideMetadata(typeof(IRCTabItem),
             //   new FrameworkPropertyMetadata(typeof(IRCTabItem)));
        }

        public static readonly RoutedEvent CloseTabEvent =
            EventManager.RegisterRoutedEvent("CloseTab", RoutingStrategy.Bubble,
                typeof(RoutedEventHandler), typeof(IRCTabItem));

        public event RoutedEventHandler CloseTab
        {
            add { AddHandler(CloseTabEvent, value); }
            remove { RemoveHandler(CloseTabEvent, value); }
        }

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

            Button closeButton = base.GetTemplateChild("PART_Close") as Button;
            if (closeButton != null)
                closeButton.Click += new System.Windows.RoutedEventHandler(closeButton_Click);
        }

        void closeButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            this.RaiseEvent(new RoutedEventArgs(CloseTabEvent, this));
        }

        public bool Closeable
        {
            get { return (bool)GetValue(CloseableProperty); }
            set { SetValue(CloseableProperty, value); }
        }
        public static readonly DependencyProperty CloseableProperty = DependencyProperty.Register("Closeable", typeof(bool), typeof(IRCTabItem), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));


        public List<String> UserList
        {
            get { return (List<string>)GetValue(UserListProperty); }
            set { SetValue(UserListProperty, value); }
        }
        public static readonly DependencyProperty UserListProperty = DependencyProperty.Register("UserList", typeof(List<String>), typeof(IRCTabItem), new FrameworkPropertyMetadata(new List<String>(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

        public String Topic
        {
            get { return (string)GetValue(TopicProperty); }
            set { SetValue(TopicProperty, value); }
        }
        public static readonly DependencyProperty TopicProperty = DependencyProperty.Register("Topic", typeof(String), typeof(IRCTabItem), new FrameworkPropertyMetadata("Not Connected", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

        public bool HasAlerts
        {
            get { return (bool)GetValue(HasAlertsProperty); }
            set { SetValue(HasAlertsProperty, value); }
        }
        public static readonly DependencyProperty HasAlertsProperty = DependencyProperty.Register("HasAlerts", typeof(bool), typeof(IRCTabItem), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));


    }

Итак, мои вопросы:

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

Редактировать 1: Добавлены предложения Питера Стивенса Редактировать 2: Добавлены видимые изменения Резюме Редактировать 3: Теги


person lloydsparkes    schedule 19.03.2010    source источник
comment
Вам, вероятно, следует добавить какой-то видимый комментарий, когда вы редактируете свой вопрос таким образом, чтобы некоторые из существующих ответов больше не имели смысла. Кроме того, когда вы внесли в код изменения, предложенные Питером Стивенсом, исправили ли они что-нибудь?   -  person Robert Rossney    schedule 19.03.2010
comment
Я думал, что добавил сводку редактирования - сделаю это сейчас. То, что предложил Питер Стивенс, не имело заметного значения.   -  person lloydsparkes    schedule 19.03.2010


Ответы (2)


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

Тема должна быть реализована так:

public String Topic 
{ 
    get { return (string) GetValue(TopicProperty); }
    set { SetValue(TopicProperty, value); }
}
public static readonly DependencyProperty TopicProperty = 
    DependencyProperty.Register("Topic", typeof(String), 
        typeof(IRCTabItem), new FrameworkPropertyMetadata("Not Connected", 
        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

Вам нужно рассматривать свойство CLR как синтаксический сахар, окружающий свойство зависимостей WPF. Позвольте свойству WPF обрабатывать хранение значения, иначе вы фактически получите два свойства с двумя разными значениями.

person Peter Stephens    schedule 19.03.2010

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

Попробуй это:

<TextBox Text="{Binding Topic, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type t:IRCTabItem}}}" />

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

person Peter Stephens    schedule 19.03.2010
comment
Спасибо за ответ. Я добавил эту модификацию, и она не меняет :( - person lloydsparkes; 19.03.2010