Behavior,Trigger,TriggerAction中使用ElementName

来源:互联网 发布:js正则test 编辑:程序博客网 时间:2024/06/05 14:14
Behavior,Trigger,TriggerAction属于元素的附加属性,并不在可视化树中,当我们在绑定的时候需要使用ElementName指定数据源的时候,ElementName是不起作用的。因为使用ElementName属性本身的元素需要在可视化树中。
  在FrameworkElement中有一个FindName函数,通过这个函数我们可以找到当前 XAML 命名空间中指定的对象。而Binding中的ElementName属性实现也是间接的调用到这个函数。  Behavior,Trigger,TriggerAction中都保存有被附加的对象,通过这个对象和FindName再加上反射,我们就可以实现ElementName。
   Behavior,Trigger,TriggerAction中并没有ElementName函数,但可以通过调用附加对象的ElementName来实现这个功能。我选择使用接口来扩展这样的功能。
  首先定义通用接口:
 interface IElementBinding    {        /// <summary>        /// 附加对象改变时触发的事件        /// </summary>        event EventHandler AssociatedObjectChanged;//附加对象改变时触发的事件        /// <summary>        /// 附加对象是否在可视化树中        /// </summary>        /// <returns></returns>        bool IsLoaded();        /// <summary>        /// 查找元素        /// </summary>        /// <param name="name"></param>        /// <returns></returns>        object FindName(string name);        /// <summary>        /// 获取继承接口的对象        /// </summary>        /// <returns></returns>        DependencyObject GetDependencyObject();    }
  我说明一下IsLoaded函数,其他的函数看注释。FindName是有使用条件的,对象本身必须处于可是化树中才可通过这个函数找到指定的对象,IsLoaded就是用来判断这个的,具体如何判断看我后面的代码。
  定义完接口然后需要一个结构来指定邦定中需要用到的属性:
 public class BindingProperties    {        /// <summary>        /// 被附加源中需要绑定的属性名称        /// </summary>        public string SourceProperty { get; set; }         /// <summary>        /// 需要绑定控件的名称        /// </summary>        public string ElementName { get; set; }        /// <summary>        /// 需要绑定控件中的目标属性        /// </summary>        public string TargetProperty { get; set; }        /// <summary>        /// 转换器        /// </summary>        public IValueConverter Converter { get; set; }    }
  下面是施行邦定的关键代码:
public class ElementBinding    {        public static BindingProperties GetBinding(DependencyObject obj)        {            if (obj == null)                return null;            return obj.GetValue(BindingProperty) as BindingProperties;        }        public static void SetBinding(DependencyObject obj, BindingProperties value)        {            obj.SetValue(BindingProperty, value);        }        public static readonly DependencyProperty BindingProperty =            DependencyProperty.RegisterAttached("Binding", typeof(BindingProperties), typeof(ElementBinding),            new PropertyMetadata(null, new PropertyChangedCallback(ElementBinding.OnBinding)));        private static void OnBinding(DependencyObject depObj, DependencyPropertyChangedEventArgs e)        {            var Interactivity = depObj as IElementBinding;            if (Interactivity == null)                return;            if (Interactivity.IsLoaded())            { CreateRelayBinding(Interactivity, GetBinding(Interactivity.GetDependencyObject())); }            else            {                Interactivity.AssociatedObjectChanged += Interactivity_AssociatedObjectChanged;            }        }        static void Interactivity_AssociatedObjectChanged(object sender, EventArgs e)        {            IElementBinding sourceElement = sender as IElementBinding;            BindingProperties bindingProperties = GetBinding(sourceElement.GetDependencyObject());            CreateRelayBinding(sourceElement, bindingProperties);        }        private static void CreateRelayBinding(IElementBinding sourceElement, BindingProperties bindingProperties)        {            if (sourceElement == null || bindingProperties == null)                return;            //获取被绑定源           var source=sourceElement.GetDependencyObject();           if (source == null)               return;           //查找目标对象            DependencyObject targetElement = sourceElement.FindName(bindingProperties.ElementName) as DependencyObject;            if (targetElement == null)                return;            //通过反射找到被绑定源中需要被绑定的附加属性            var sourceDependencyPropertyField = source.GetType().GetField(bindingProperties.SourceProperty + "Property", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);            if (sourceDependencyPropertyField == null)                return;            DependencyProperty sourceDependencyProperty = sourceDependencyPropertyField.GetValue(null) as DependencyProperty;            Binding binding = new Binding();            binding.Source = targetElement;            binding.Path = new PropertyPath(bindingProperties.TargetProperty);            binding.Converter = bindingProperties.Converter;            //绑定            BindingOperations.SetBinding(source, sourceDependencyProperty, binding);        }        public static bool IsElementLoaded(FrameworkElement element)        {            if (element == null)                return false;            UIElement rootVisual = Application.Current.RootVisual;            DependencyObject parent = element.Parent;            if (parent == null)            {                parent = System.Windows.Media.VisualTreeHelper.GetParent(element);            }            return parent != null || (rootVisual != null && element == rootVisual);        }    }
  邦定的过程在CreateRelayBinding函数中。
  邦定流程好了以后可以开始对Behavior,Trigger,TriggerAction进行改造了。邦定中TriggerAction用的比较多,我就
以这个为例子,Behavior和Trigger自行扩展。
  首先自己定义一个TriggerAction基类,所有自定义的TriggerAction都从这个基类继承,然后再里面实现IElementBinding的所有接口。注意:不实现IElementBinding接口是无法使用ElementBinding类的。
 public abstract class CustomTriggerActionBase : TriggerAction<FrameworkElement>, IElementBinding    {        public event EventHandler AssociatedObjectChanged;        protected override void OnAttached()        {            base.OnAttached();            if (ElementBinding.IsElementLoaded(this.AssociatedObject) && AssociatedObjectChanged != null)                AssociatedObjectChanged(this, new EventArgs());            else if (this.AssociatedObject != null)                this.AssociatedObject.Loaded += AssociatedObject_Loaded;        }        protected override void OnDetaching()        {            base.OnDetaching();            this.AssociatedObject.Loaded -= AssociatedObject_Loaded;        }        void AssociatedObject_Loaded(object sender, RoutedEventArgs e)        {            if (AssociatedObjectChanged != null)                AssociatedObjectChanged(this, new EventArgs());        }        public bool IsLoaded()        {            return ElementBinding.IsElementLoaded(this.AssociatedObject);        }        public object FindName(string name)        {            return this.AssociatedObject == null ? null : this.AssociatedObject.FindName(name);        }        public DependencyObject GetDependencyObject()        {            return this;        }    }
  使用起来很简单,比如我们有一个NavigateAction,用来导航,里面有一个Parameter,用来向下一个页面传递参数,
使用时这样写:
            <Button Content="To Page1" Width="200" Height="80" >                <i:Interaction.Triggers>                    <i:EventTrigger EventName="Click">                        <local:NavigateAction NavigateName="/Page1.xaml">                            <local:ElementBinding.Binding>                                <local:BindingProperties SourceProperty="Parameter" ElementName="ParameterText" TargetProperty="Text"/>                            </local:ElementBinding.Binding>                        </local:NavigateAction>                    </i:EventTrigger>                </i:Interaction.Triggers>            </Button>
  导航前界面:
  
  导航后的界面:

  示例代码:

ElementBindingText.zip


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 坚果pro无法双清怎么办 usb外置网卡网速慢怎么办? 无线路由器被改密码怎么办 电脑打不开flv格式的视频怎么办 电脑打不开pdf格式的文件怎么办 pdf格式在电脑上打不开怎么办 zip压缩的时候空间不足怎么办 电子发票填抬头错了怎么办 发票写错一个字怎么办 普票税率开错了怎么办 税率开错为17了怎么办 电子发票抬头错了怎么办 发票抬头错了一个字怎么办 5月税率开错了怎么办 如果发票是假的怎么办 发票收款人名字写错了怎么办 医院发票名字写错了怎么办 购买方发票联丢失怎么办 市中区超市办理发票怎么办 发票购买薄丢了怎么办 发票领用簿丢了怎么办 摩托车证扣12分怎么办 初中孩孑想扩展单词量怎么办 恒安保险倒闭了怎么办 小麦收割机卸粮筒总是转怎么办 非牛顿体结块了怎么办 非牛顿流体硬了怎么办 玩具枪子弹打到眼睛怎么办 杭州磨床7130噪音大怎么办 步兵太苦还有一年怎么办 检法事业编怎么办最新 河北省事业单位改企编制怎么办 梦飞去虎牙锐雯怎么办 蚂蚁借呗还款钱没到账怎么办 蚂蚁借呗没有按时还款怎么办 新装的win7没有网卡驱动怎么办 3d电影没眼睛怎么办 看vr手机发烫变卡怎么办 vr眼镜头晕想吐怎么办 程序员年龄大了失业怎么办 事业人员编制在机关任职改革怎么办