• 为什么这儿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。

  • 相关阅读:
    Java并发/多线程-线程池的使用
    pam详解
    chrony时间同步服务
    网站每日UV数据指标去重统计
    阻塞式发送邮件
    待办事项-redis
    解决Windows7、Windows10 ping不通的问题
    redis序列化和反序列化的操作-(以前咋操作我都忘记了)
    秒杀活动下的公平队列抢购机制
    控制某个字段不在页面展示
  • 原文地址:https://www.cnblogs.com/zxmoe992/p/3127030.html
Copyright © 2020-2023  润新知