1

我已经为此苦苦挣扎了一段时间,在 WindowForms 中做起来很简单。

我正在制作一个 IRC 客户端,每个连接到的频道都会有多个选项卡。每个 Tab 都需要显示一些东西,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:添加 Peter Stephens 建议 编辑 2:添加可见编辑摘要 编辑 3:标签

4

2 回答 2

0

One problem you have is that your dependency properties are implemented incorrectly.

Topic should be implemented like so:

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

You need to treat the CLR property as syntactic sugar surrounding the WPF dependency property. Let the WPF property handle the storage of the value, otherwise you will effectively have two properties with two different values.

于 2010-03-19T12:14:57.133 回答
0

我相信您的绑定表达式缺少相对来源的模式。

尝试这个:

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

Mode 的默认值为 null,因此如果您不包括该设置,则设置可能不会那么好。

于 2010-03-19T15:35:39.267 回答