zoukankan      html  css  js  c++  java
  • Sliverlight Tip 让DataGrid支持Scroll事件

    Silverlight4.0的DataGrid标准控件中只开放了极少的控件事件提供给开发者使用,像DoubleClick,Scroll之类比较常见的事件都没有做支持.
    对于DoubleClick的处理,可以通过Behavior进行变通,这不是本次要讲解的技术内容.
    这次要讲解的是如何注册Scroll事件到DataGrid的垂直或水平滚动条.
     
    先通过Refector查看了DataGrid的实现,确实包含VerticalScrollBar和 HorizontalScrollBar这两个属性,可惜声明为internal,只能在程序集内部被调用.
    因此下意识的是用反射机制拿到Scroll对象,然后注册事件,于是先尝试如下代码:
    /// <summary>
    /// 尝试使用反射获取VerticalScrollbar属性以得到Scrollbar对象
    /// </summary>
    private void TryUseReflectProperty()
    {
    var propInfo
    = typeof(DataGrid).GetProperty("VerticalScrollBar",
    BindingFlags.Instance | BindingFlags.NonPublic);
    if (propInfo != null)
    {
    ScrollBar scroll
    = propInfo.GetValue(dataGrid, null) as ScrollBar;
    }
    }
    可惜执行到GetValue处直接跳出异常,
    原来出于安全性的考虑,Silverlight程序是无法通过反射来访问到私有的属性,成员,方法,事件,.etc
    具体说明可以参考MSDN: http://msdn.microsoft.com/en-us/library/stfy7tfc(VS.95).aspx

    其实在没有找到MS的官方说明之前,我又尝试了一些其他跟Reflection有关的方法,
    比如尝试先获取MethodInfo再尝试Invoke(该做法跟Property的尝试异曲同工,没有本质改进),
    后来又尝试通过MethodInfo创建另一个委托,再通过DynamicInvoke去做,可惜仍然是徒劳无功.

    无奈之下继续Google,发现有一种解决方案是在DataGrid的Style Template里直接绑定Scroll事件,
    通过Blend打开看确实能够找到DataGrid对应的VerticalScrollBar和HorizontalScrollBar.

    这样的做法给了一些启发,或者说是灵感,既然如此,直接操作VisualTree应该能够获取到ScrollBar,
    于是行动之...
    /// <summary>
    /// 通过VisualTreeHelper,递归找到ScrollBar
    /// </summary>
    private ScrollBar GetScrollbar(DependencyObject dpObj, string name)
    {
    for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dpObj); i++)
    {
    var child
    = VisualTreeHelper.GetChild(dpObj, i);
    ScrollBar scrollBar
    = child as ScrollBar;
    if (scrollBar != null && scrollBar.Name == name)
    {
    return scrollBar;
    }
    else
    {
    scrollBar
    = GetScrollbar(child, name);
    if (scrollBar != null)
    {
    return scrollBar;
    }
    }
    }
    return null;
    }
    结果发现果然可以,那么该在何时去调用GetScrollBar并注册Scroll事件呢?
    个人推荐是在LayoutUpdated事件里做一次处理,具体代码如下:
     
    ScrollBar scroll;
    /// <summary>
    /// 尝试通过VistualTree来找到Scrollbar对象
    /// </summary>
    private void TryUseVisualTree()
    {
    EventHandler h
    = null;
    dataGrid.LayoutUpdated
    += h = delegate
    {
    if (scroll == null)
    {
    scroll
    = GetScrollbar(dataGrid, "VerticalScrollBar");
    if (scroll != null)
    {
    //一旦找到注销LayoutUpdated事件
    dataGrid.LayoutUpdated -= h;
    //注册Scroll事件
    scroll.Scroll += delegate { Debug.WriteLine("scrolling..."); };
    }
    }
    };
    }
    大功告成,这样我们就能够在代码里处理Scroll事件了.
    这个例子很好扩展,对于DataGrid内含的各种UIElement如果直接访问不到,都可以通过查找VistualTree的方法找到,并执行相应的处理.
    而且不仅仅限于DataGrid,任何其他的UIElement都可能会碰到类似的需求,并给出类似的解决方法.
     
  • 相关阅读:
    如何理解c和c++ 的复杂类型声明
    xp自带扫雷bug
    求三角形的外接圆
    判断一个点是否在一个三角形内
    三角函数角度公式
    弗洛伊德(Floyd)算法
    在Win32应用程序中用Console控制台输出信息
    无法打开libcp.lib
    C#获取当前应用程序所在路径及环境变量
    C#事件的发送方和接收方(订阅方)【转】
  • 原文地址:https://www.cnblogs.com/bloodish/p/1990386.html
Copyright © 2011-2022 走看看