• 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都可能会碰到类似的需求,并给出类似的解决方法.
     
  • 相关阅读:
    借贷宝什么鬼 砸钱推广是妙招还是险棋
    div+css 怎么让一个小div在另一个大div里面 垂直居中
    php重新整理数组索引
    JS 得细心的坑位
    chrome表单自动填充导致input文本框背景变成偏黄色问题解决
    phpstorm配置xdebug
    MySQLi基于面向对象的编程
    PHP中开启gzip压缩的2种方法
    SVN创建主干,分支、合并分支
    懒加载和预加载【转载】
  • 原文地址:https://www.cnblogs.com/bloodish/p/1990386.html
Copyright © 2020-2023  润新知