silverlight4-简单的FindAncestor绑定

在WPF和SL5中都有RelativeSource是FindAncestor绑定,这是个很实用的绑定功能,特别是在配置模板的时候。可惜SL4里还没有,让我们来通过几个辅助类简单的实现一下。

主要思路还是通过VisualTreeHelper获取Parent来实现绑定。


新建解决方案,添加个类叫做AncestorBinding提供一下绑定需要的基本属性,如下:

ContractedBlock.gif ExpandedBlockStart.gif View Code
    public class AncestorBinding
{
public string AncestorPath { get; set; }
public string AncestorTypeName { get; set; }
public string TargetPath { get; set; }
public IValueConverter Converter { get; set; }
}


再添加类BindingHelper用以提供绑定用的附加属性,如下:

ContractedBlock.gif ExpandedBlockStart.gif View Code
    public class BindingHelper
{
public static AncestorBinding GetAncestorBinding(DependencyObject target)
{
if (target == null)
throw new ArgumentNullException("target");

return (AncestorBinding)target.GetValue(AncestorBindingProperty);
}

public static void SetAncestorBinding(DependencyObject target, AncestorBinding value)
{
if (target == null)
throw new ArgumentNullException("target");

target.SetValue(AncestorBindingProperty, value);
}

public static readonly DependencyProperty AncestorBindingProperty =
DependencyProperty.RegisterAttached(
"AncestorBinding", typeof(AncestorBinding), typeof(FrameworkElement),
new PropertyMetadata(OnAncestorChanged));

private static void OnAncestorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ancestorBinding
= e.NewValue as AncestorBinding;
if (ancestorBinding == null)
throw new ArgumentNullException("AncestorBinding");

var element
= d as FrameworkElement;
if (element == null)
throw new ArgumentNullException("target");

ancestorBinding.SetBinding(element);
}
}


可见在
AncestorBinding需要提供个SetBinding的方法,实现如下:

ContractedBlock.gif ExpandedBlockStart.gif View Code
    public class AncestorBinding
{
internal void SetBinding(FrameworkElement element)
{
if (string.IsNullOrWhiteSpace(this.AncestorTypeName))
throw new ArgumentNullException("AncestorTypeName");

if (string.IsNullOrWhiteSpace(this.TargetPath))
throw new ArgumentNullException("TargetPath");

if (this.TryBinding(element) == false)
{
element.Loaded
+= ElementLoaded;
}
}

private void ElementLoaded(object sender, RoutedEventArgs e)
{
var element
= sender as FrameworkElement;
element.Loaded
-= ElementLoaded;

this.TryBinding(element);
}

private bool TryBinding(FrameworkElement element)
{
var dp
= element.GetDependencyProperty(this.TargetPath);
if (dp == null)
return false;

var ancestor
= element.FindAncestor(this.AncestorTypeName);
if (ancestor == null)
return false;

var binding
= new Binding
{
Source
= ancestor,
Converter
= this.Converter
};

if (!string.IsNullOrEmpty(this.AncestorPath))
{
binding.Path
= new PropertyPath(this.AncestorPath);
}

element.SetBinding(dp, binding);
return true;
}
}

因为设置绑定的时候控件可能还没加载,这样就会溯源失败,所以如果失败就需要在Load之后再尝试绑定一次。

在TryBinding中获取需要绑定的目标依赖属性和溯源控件,如果都成功获取就设置绑定。

再看一下TryBinding用到的两个扩展方法,添加静态类FrameworkElementExtensions,如下:

ContractedBlock.gif ExpandedBlockStart.gif View Code
    public static class FrameworkElementExtensions
{
internal static DependencyProperty GetDependencyProperty(this FrameworkElement element, string propertyName)
{
if (element == null || string.IsNullOrEmpty(propertyName))
return null;

var dpInfo
= element.GetType().GetField(propertyName + "Property", BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy);
if (dpInfo == null)
return null;

return dpInfo.GetValue(element) as DependencyProperty;
}

internal static object FindAncestor(this FrameworkElement element, string ancestorTypeName)
{
if (string.IsNullOrEmpty(ancestorTypeName))
return null;

while (element != null)
{
if (IsTypeMatch(element, ancestorTypeName))
return element;

if (IsTypeMatch(element.DataContext, ancestorTypeName))
return element.DataContext;

element
= VisualTreeHelper.GetParent(element) as FrameworkElement;
}

return null;
}

private static bool IsTypeMatch(object obj, string typeName)
{
if (obj == null || string.IsNullOrEmpty(typeName))
return false;

var type
= obj.GetType();
var interfaces
= type.GetInterfaces();
if (interfaces != null && interfaces.Any(p => p.Name == typeName))
return true;

while (type != null)
{
if (type.Name == typeName)
return true;

type
= type.BaseType;
}

return false;
}
}

获取附加属性的方法GetDependencyProperty是通过简单的反射来实现。

溯源的方法FindAncestor是通过VisualTreeHelper来实现,为了更好的溯源,此处对DataContenxt也进行了匹配搜索。

代码就是这么多,挺简单,看看就明白。简单测试一下吧。

ContractedBlock.gif ExpandedBlockStart.gif View Code
        <Button Margin="1,2,3,4" Height="30" Width="150">
<TextBlock >
<local:BindingHelper.AncestorBinding>
<local:AncestorBinding TargetPath="Text" AncestorPath="Margin" AncestorTypeName="Button"/>
</local:BindingHelper.AncestorBinding>
</TextBlock>
</Button>

这个示例比较简单,只是把Text属性绑定到Button的Margin上。实际应用中可能在设置模板的时候用到的更多。

效果:

代码:BindingExtensions

RelativeSource

转载于:https://www.cnblogs.com/HalfwayMonk/archive/2011/07/14/2106908.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值