我一直在讨论这个问题,在WindowForms中做起来很简单。
我正在制作一个IRC客户端,每个频道的连接都会有一个选项卡。 每个选项卡都需要显示许多内容,UserList,MessageHistory,Topic。
在WindowForms中,我只是从TabItem继承,添加了一些自定义属性和控件,并完成了。
在WPF中,我在解决如何操作方面遇到了一些小问题。
我尝试了很多方法,下面是我当前的方法,但我无法将TextBox绑定到Topic属性。
<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>
和Codebehind
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绑定到Properties? 如果不是这样,那么实现我想要实现的目标的正确方法是什么?
编辑1:添加了Peter Stephens的建议 编辑2:添加了可见编辑摘要 编辑3:标签
答案 0 :(得分:0)
您遇到的一个问题是您的依赖项属性实现不正确。
主题应该像这样实现:
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属性处理值的存储,否则您将有效地拥有两个具有两个不同值的属性。
答案 1 :(得分:0)
我相信您的绑定表达式缺少相对来源的模式。
试试这个:
<TextBox Text="{Binding Topic, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type t:IRCTabItem}}}" />
Mode的默认值为null,所以如果你不包含那个设置,事情可能就不会那么好了。