为什么这儿TemplateBinding不起作用了—研究WPF Binding(一)

工作中,写自定义控件,遇到一个奇怪的问题。场景是这样的:一个ListBox或其他ItemsControl显示数据列表,下方一个TextBlock显示列表中选定的值,代码大概是这样的(做了简化):

<Border Background="{TemplateBinding Background}"
        BorderBrush="{TemplateBinding BorderBrush}"
        BorderThickness="{TemplateBinding BorderThickness}">
     <StackPanel>
         <ListBox ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent},Path=TimeDataSource.Months}"
                  SelectedValue="{TemplateBinding Month}" VerticalContentAlignment="Top">
         </ListBox>
         <TextBlock Text="{TemplateBinding Month}"/>
     </StackPanel>
</Border>

Month是后台定义的依赖属性,现在的问题是,ListBox拿到了数据(1到12个月),但下方的TextBlock却显示不出列表的SelectedValue,必须把它的代码换成这样才行:

<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Month}"/>

用snoop抓取也会看到后面一种情形,Text属性才能拿到值。显然要查清楚问题所在必须研究一下TemplateBinding。

按照MSDN和网络上看到的解释,TemplateBinding主要用于模版,属于优化的Binding但精简了继承内容引用和动态类型转换等很多功能,它等效于:{Binding RelativeSource={RelativeSource TemplatedParent}}。看到这儿品味出什么了吧,对,类型转换!它所绑定的依赖属性Month是Int类型,而TextBlock的Text属性是String类型,如果用普通Binding,WPF能自动帮你做转换,而TemplateBinding就不行了。无独有偶,几个月前我写过一个小控件,一个要求是输入框(TextBox)前面的文本说明是可以设置的,比如“柜员账号”或其他什么名称,我定义的InputName属性是String类型,用TemplateBinding和TextBlock绑在一起就可以正常运行。那就再定义一个String类型的依赖属性,试试看:

public static readonly DependencyProperty MonthStringProperty =
            DependencyProperty.Register("MonthString", typeof(String), typeof(ControlTest),
                                        new FrameworkPropertyMetadata(DateTime.Now.Month.ToString()));

        public String MonthString
        {
            get { return GetValue(MonthStringProperty).ToString(); }
            set { SetValue(MonthStringProperty, value); }
        }

前台Xaml如下:

<Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <StackPanel>
                            <TextBlock Text="{TemplateBinding MonthString}"/>
                            <ListBox ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent},Path=TimeDataSource.Months}"
                                 SelectedValue="{TemplateBinding Month}" VerticalContentAlignment="Top">
                            </ListBox>
                            <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Month}"/>
                        </StackPanel>
                    </Border>

果然,数据能显示了:

所以,可以得出:TemplateBinding的源和目标类型必须完全一致,如果它们之间需要类型转换,只能改成{Binding RelativeSource}的形式,或者定义依赖属性时注意一下类型,这里Month由于后面涉及一些计算必须定义为int。

转载于:https://www.cnblogs.com/zxmoe992/archive/2013/06/08/3127030.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的WPF自定义下拉框控件的实现: 1. 创建一个新的WPF控件项目,命名为“CustomComboBox”。 2. 在项目中添加一个新的类,命名为“CustomComboBox.cs”,在类中添加以下代码: ``` using System.Windows; using System.Windows.Controls; namespace CustomComboBox { public class CustomComboBox : ComboBox { static CustomComboBox() { DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomComboBox), new FrameworkPropertyMetadata(typeof(CustomComboBox))); } } } ``` 这里我们继承了WPF内置的`ComboBox`控件,并重写了`DefaultStyleKeyProperty`属性,这是自定义控件的必要步骤之一。 3. 在项目中添加一个新的资源字典,命名为“Generic.xaml”,并添加以下代码: ``` <Style TargetType="{x:Type local:CustomComboBox}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:CustomComboBox}"> <Grid> <ToggleButton x:Name="PART_ToggleButton" Grid.Column="2" Focusable="false" IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition Width="20" /> </Grid.ColumnDefinitions> <Border x:Name="Border" Grid.ColumnSpan="2" CornerRadius="0" Background="White" BorderBrush="Black" BorderThickness="1" /> <Path x:Name="Arrow" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M 0 0 L 4 4 L 8 0 Z" /> </Grid> </ToggleButton> <Popup x:Name="PART_Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True" Focusable="False" PopupAnimation="Slide"> <Border x:Name="PopupBorder" Background="White" BorderBrush="Black" BorderThickness="1" CornerRadius="0"> <ScrollViewer x:Name="ScrollViewer" SnapsToDevicePixels="True"> <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" /> </ScrollViewer> </Border> </Popup> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsEnabled" Value="False"> <Setter Property="Foreground" Value="#888888" /> </Trigger> <Trigger Property="IsGrouping" Value="True"> <Setter Property="ScrollViewer.CanContentScroll" Value="False" /> </Trigger> <Trigger SourceName="PopupBorder" Property="BorderThickness" Value="0"> <Setter TargetName="Border" Property="Margin" Value="0" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> ``` 这里定义了一个名为“CustomComboBox”的样式,它继承自WPF内置的`ComboBox`样式,并在其中添加了一个`ToggleButton`控件,用于展开/收起下拉框,以及一个`Popup`控件,用于显示下拉框中的内容。 4. 在项目中添加一个新的XAML文件,命名为“MainWindow.xaml”,并添加以下代码: ``` <Window x:Class="CustomComboBox.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:CustomComboBox" Title="MainWindow" Height="350" Width="525"> <Grid> <local:CustomComboBox Width="150" Height="30"> <ComboBoxItem>Item 1</ComboBoxItem> <ComboBoxItem>Item 2</ComboBoxItem> <ComboBoxItem>Item 3</ComboBoxItem> </local:CustomComboBox> </Grid> </Window> ``` 这里我们在窗口中添加了一个自定义下拉框控件,并在其中添加了三个选项。 5. 运行程序,你将看到一个自定义的下拉框控件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值