[Silverlight]山寨方法->扩展方法->Behavior以及一些遗憾

在我前两日的博文让DataGrid支持滚轮的山寨方法中所提到的方法非常Dirty,由于本人较懒且项目中只有一个地方应用了这个滚轮设计所以也未将其封装起来。所以嘛。。想复用就得ctrl+c、ctrl+v(这年头这种做法的确雷人)。

扩展方法

不过天底下有懒人就有勤快人,在那篇文章的回复中,dongdongha[未注册用户]兄弟将此方法提炼了出来以便复用,代码如下:

public static void SetMouseScroll<T>(this DataGrid dataGrid) {
    dataGrid.MouseWheel += (sender, e) => {
        DataGrid dataGrid1 = sender as DataGrid;
        if (dataGrid.ItemsSource == null) 
            return;

        if (!e.Handled) {
            int rowsToMove = e.Delta / 120 * -1;

            if (e.Delta > 0) {
                if (dataGrid1.SelectedIndex + rowsToMove < 0) 
                    return;              
            }
            else {
                if (dataGrid1.SelectedIndex + rowsToMove > dataGrid1.ItemsSource.Cast<T>().ToList().Count - 1) 
                    return;            
            }

            dataGrid1.SelectedIndex = dataGrid1.SelectedIndex + rowsToMove;
            dataGrid1.ScrollIntoView(dataGrid1.SelectedItem, dataGrid1.Columns[0]);
        }
    };
}

(注:这兄弟原文中用的是匿名委托,本着能少写就少写的理念,那部分给小改成Lambda了)

通过扩展方法和使用泛型,使得方法的复用性大大增加

调用方式

dataGrid1.SetMouseScroll<Person>();

的确是很方便~

ok,第一步改造就此结束

Behavior

接下来由于我在原文中提到了Behavior,所以就干脆用Behavior再封装一次,核心代码其实还是上面的。

public class DataGridMouseWheelBehavior<T> : Behavior<DataGrid> {

    public string TypeOfBehavior { get; set; }

    public DataGridMouseWheelBehavior() { }

    protected override void OnAttached() {
        base.OnAttached();
        this.AssociatedObject.Loaded += new RoutedEventHandler(AssociatedObject_Loaded);

    }

    void AssociatedObject_Loaded(object sender, RoutedEventArgs e) {
        DataGrid dg = sender as DataGrid;
        dg.MouseWheel += (s2, e2) => {
            if (!e2.Handled) {
                int rowsToMove = e2.Delta / 120 * -1;

                if (e2.Delta > 0) {
                    if (dg.SelectedIndex + rowsToMove < 0)
                        return;
                }
                else {
                    if (dg.SelectedIndex + rowsToMove > dg.ItemsSource.Cast<T>().ToList().Count - 1)
                        return;
                }

                dg.SelectedIndex = dg.SelectedIndex + rowsToMove;
                dg.ScrollIntoView(dg.SelectedItem, dg.Columns[0]);
            }
        };
    }

    protected override void OnDetaching() {
        base.OnDetaching();
    }
}

调用方式

var mousebehavior = new DataGridMouseWheelBehavior<Person>();
mousebehavior.Attach(dataGrid1);

这个调用方式看起来不如扩展方法

  • 非静态,需要实例化
  • 必须Attach,没有扩展方法那么优雅

但其实Behavior的真正意义在于可以在XAML中应用。也就是说Developer封装过的方法,Designer不用知道它到底是如何实现的,只要清楚它是用来做什么的就可以了。美工可以通过Blend非常方便的使用Behavior,在XMAL的标记方式为

<i:Interaction.Behaviors>
    <local:DataGridMouseWheelBehavior />
</i:Interaction.Behaviors>

看上去的确很爽。但为什么我们在这里要使用代码调用的方式而非XAML标记呢?这的确是个遗憾。

关键就在于:<T>---对,就是泛型。XAML中并不支持泛型的声明(这点在WPF中稍好一些,不过依然很弱)。

如果强制的使用Person那么就丧失了Behavior的灵活性,还不如不封装。

这同时也证明我这个例子并不非常适合封装成Behavior

现在我知道的解决方案也只能是苦等盼望随着.NET4.0而来的XAML2009了。

或许您有更好的方法,何不告诉我呢?

posted @ 2009-12-24 20:46  紫色永恒  阅读(1580)  评论(8编辑  收藏  举报