WPF架构关键技术剖析(3)--做自己的交互Action(2)

下面我们利用附加属性,将我们准备好的Action集合能作为附加属性出现在xaml中:

1)附加属性类:

/// <summary>
/// 附加属性定义类,注意必须是静态的,这有点类似于给类增加扩展方法。
/// </summary>
public static class WPFTestDettach
{
/// <summary>
/// 注册附加属性。
/// </summary>
public static readonly DependencyProperty MyObjectsProperty =
DependencyProperty.RegisterAttached("MyObjects", typeof(MyActionCollection), typeof(WPFTestDettach),
new PropertyMetadata(null,(dobj,darg)=>{

//一般情况下这里可以不要。附加属性的目的是切入,而不会关心其属性的变化。
}));
/// <summary>
/// 这个方法是必须的,命名也有规则MyObjects =》 MyObjectsProperty = GetMyObjects。
/// 便于解释分析器获取该方法.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static MyActionCollection GetMyObjects(DependencyObject obj)
{
MyActionCollection theC = (MyActionCollection)(obj.GetValue(MyObjectsProperty));
if (theC == null)
{
theC = new MyActionCollection();
obj.SetValue(MyObjectsProperty, theC);
}
theC.Obj = obj;
return theC;
}
//设置方法类似,不过这里没什么用处,所以从略.
}

2)定义好了附加属性,就可以用了,如何用,我们暂且不管,先看看,我们如何达到我们在前面一篇所提到的目的,这里我们实现一个具体的Action

/// <summary>
/// 具体的Action应用,面向TreeView类,可以截获事件,并执行相应的方法.
/// </summary>
public class MyActionTest : MyAction<TreeView>
{
/// <summary>
/// 挂接事件的地方,切入点.
/// </summary>
public override void OnAttached()
{
base.OnAttached();
//利用反射可以获取到对象的事件信息,并动态设置连接
//这里因为只是测试,所以简化。
switch (EventName)
{
case "SelectedItemChanged":
this.WObj.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(MyWPF_SelectedItemChanged);
break;
}

}
/// <summary>
/// 接挂的地方,清楚事件处理挂接,释放不必要的资源.
/// </summary>
public override void OnDetaching()
{
base.OnDetaching();
switch (EventName)
{
case "SelectedItemChanged":
this.WObj.SelectedItemChanged -= new RoutedPropertyChangedEventHandler<object>(MyWPF_SelectedItemChanged);
break;
}
}
/// <summary>
/// 事件处理的地方。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void MyWPF_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
DoSomething(Params);
}
/// <summary>
/// 公开属性可通过Xaml中设置,EventName 要触发的时间名.
/// </summary>
public string EventName { get; set; }
/// <summary>
/// 参数字符串
/// </summary>
public string Params { get; set; }
/// <summary>
/// 目标对象,可以是当前页面的UI元素。当然,你也可以自己规定规则,做的非常复杂。
/// </summary>
public string TargetName { get; set; }
/// <summary>
/// 目标对象上的方法名,就是你需要执行的,注意对象上的这种方法必须是公共的.
/// </summary>
public string MethodName { get; set; }
/// <summary>
/// 具体事件处理,这里用到了反射.
/// </summary>
/// <param name="PMs"></param>
public void DoSomething(string PMs)
{

object theRootObj = GetRootObject(this.WObj);
object theTargetObj = null;
//如果目标元素为空,则取页面root element.
if (TargetName == "")
{
theTargetObj = theRootObj;
}
else
{
//获取目标UI元素.
theTargetObj = ((FrameworkElement)theRootObj).FindName(TargetName);
}
//获取目标方法并调用.
MethodInfo theMI = theTargetObj.GetType().GetMethod(MethodName);
if (theMI != null)
{
theMI.Invoke(theTargetObj,new object[]{PMs});
}

}
/// <summary>
/// 一个自定义的辅助函数,用于获取页面的根结点,这样可以查找本页的UI元素.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
private FrameworkElement GetRootObject(FrameworkElement obj)
{
if (obj.Parent != null && obj.Parent is FrameworkElement)
{
return GetRootObject((FrameworkElement)(obj.Parent));
}
return obj;
}
}

做好了准备,下面我们就可以应用了.....待续

你可能感兴趣的:(action)