MVVM WPF 中的 ListBox 滚动事件 [英] ListBox scrolling event in MVVM WPF

查看:42
本文介绍了MVVM WPF 中的 ListBox 滚动事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法以 MVVM 的方式在 WPF (Windows Phone7) 中挂钩滚动事件?我想检测列表何时滚动到底部,然后执行某些操作.我试过这样的事情,但显然它不会工作:

<i:Interaction.Triggers><i:EventTrigger EventName="点击"><i:InvokeCommandAction Command="{Binding ListBoxClick}"/></i:EventTrigger><i:EventTrigger EventName="滚动"><i:InvokeCommandAction Command="{Binding ListBoxScroll}"/></i:EventTrigger></i:Interaction.Triggers>(……)</列表框>

解决方案

在这种情况下,我总是看附加行为的方向,因为我们需要一个独立的解决方案,可以在旁边工作UI 和 MVVM 风格.附加行为 - 是一个附加属性,它有一个事件处理程序来改变这个属性,所有的逻辑都在这个处理程序中实现.

在这种情况下,您需要传递一个指示行为开始的布尔值,以及当我们的条件执行时执行的命令 - 滚动到 ListBox 的末尾.

我创建了一个示例行为,其中关键逻辑在这里:

private static void scrollViewerScrollChanged(object sender, ScrollChangedEventArgs e){var scrollViewer = sender as ScrollViewer;如果(滚动查看器!= null){//这里我们判断是否到达底部如果(scrollViewer.VerticalOffset == scrollViewer.ScrollableHeight){命令 = GetCommand(listBox);//执行命令命令.执行(列表框);}}}

使用示例:

XAML

<local:TestViewModel/></Window.DataContext><窗口.资源><x:Array x:Key="TestArray" Type="{x:Type sys:String}"><sys:String>Test1</sys:String><sys:String>Test2</sys:String><sys:String>Test3</sys:String><sys:String>Test4</sys:String><sys:String>Test5</sys:String><sys:String>Test6</sys:String><sys:String>Test7</sys:String><sys:String>Test8</sys:String><sys:String>Test9</sys:String><sys:String>Test10</sys:String></x:数组></Window.Resources><网格><列表框名称=测试列表框"AttachedBehaviors:ScrollingToBottomBehavior.IsEnabled="True"AttachedBehaviors:ScrollingToBottomBehavior.Command="{Binding TestButtonCommand}"ItemsSource="{StaticResource TestArray}"高度=50"/></网格>

TestViewModel

公共类TestViewModel{私人 ICommand _testButtonCommand = null;公共 ICommand 测试按钮命令{得到{if (_testButtonCommand == null){_testButtonCommand = new RelayCommand(param => this.TestButton(), null);}返回 _testButtonCommand;}}私有无效 TestButton(){MessageBox.Show("测试命令执行");}}

ScrollingToBottomBehavior

公共类ScrollingToBottomBehavior{#region 私人部分私有静态列表框 listBox = null;私有静态 ICommand 命令 = null;#endregion#region IsEnabledPropertypublic static readonly DependencyProperty IsEnabledProperty;public static void SetIsEnabled(DependencyObject DepObject, 字符串值){DepObject.SetValue(IsEnabledProperty, value);}public static bool GetIsEnabled(DependencyObject DepObject){返回(布尔)DepObject.GetValue(IsEnabledProperty);}#endregion#region 命令属性public static readonly DependencyProperty CommandProperty;public static void SetCommand(DependencyObject DepObject, ICommand 值){DepObject.SetValue(CommandProperty, value);}公共静态 ICommand GetCommand(DependencyObject DepObject){返回(ICommand)DepObject.GetValue(CommandProperty);}静态 ScrollingToBottomBehavior(){IsEnabledProperty = DependencyProperty.RegisterAttached("IsEnabled",类型(布尔),typeof(ScrollingToBottomBehavior),新的 UIPropertyMetadata(false, IsFrontTurn));CommandProperty = DependencyProperty.RegisterAttached("Command",类型(ICommand),typeof(ScrollingToBottomBehavior));}#endregionprivate static void IsFrontTurn(DependencyObject sender, DependencyPropertyChangedEventArgs e){listBox = 发件人为列表框;如果(列表框 == 空){返回;}if (e.NewValue is bool && ((bool)e.NewValue) == true){listBox.Loaded += new RoutedEventHandler(listBoxLoaded);}别的{listBox.Loaded -= new RoutedEventHandler(listBoxLoaded);}}private static void listBoxLoaded(object sender, RoutedEventArgs e){var scrollViewer = GetFirstChildOfType(listBox);如果(滚动查看器!= null){scrollViewer.ScrollChanged += new ScrollChangedEventHandler(scrollViewerScrollChanged);}}#region GetFirstChildOfTypeprivate static T GetFirstChildOfType(DependencyObject dependencyObject) 其中 T : DependencyObject{if (dependencyObject == null){返回空;}for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++){var child = VisualTreeHelper.GetChild(dependencyObject, i);var 结果 = (child as T) ??GetFirstChildOfType(child);如果(结果!= null){返回结果;}}返回空;}#endregionprivate static void scrollViewerScrollChanged(object sender, ScrollChangedEventArgs e){var scrollViewer = sender as ScrollViewer;如果(滚动查看器!= null){如果(scrollViewer.VerticalOffset == scrollViewer.ScrollableHeight){命令 = GetCommand(listBox);命令.执行(列表框);}}}}

<块引用>

完整的示例项目可用 <代码>此处.

Is there a way to hook to scroll event in WPF (Windows Phone7), in a MVVM manner? I'd like to detect when the list is scrolled to the bottom, and then do something. I tried something like this, but obviously it won't work:

<ListBox ItemsSource="{Binding Places}" SelectedItem="{Binding SelectedPlace, Mode=TwoWay}">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Tap">
            <i:InvokeCommandAction Command="{Binding ListBoxClick}"/>
        </i:EventTrigger>
        <i:EventTrigger EventName="Scroll">
            <i:InvokeCommandAction Command="{Binding ListBoxScroll}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    (...)
</ListBox>

解决方案

In this situation, I always look in the direction of attached behavior, because we need an independent solution that would work on the side UI and in the MVVM style. Attached behavior - is an attached property, which has an event handler to change this property and all the logic is implemented in this handler.

In this case you need to pass a Boolean value that indicates the beginning of behavior, and the command, what be executed when our condition is perform - scroll to the end of ListBox.

I created an example behavior where the key logic is here:

private static void scrollViewerScrollChanged(object sender, ScrollChangedEventArgs e)
{
    var scrollViewer = sender as ScrollViewer;

    if (scrollViewer != null)
    {
        // Here we determine if the bottom reached
        if (scrollViewer.VerticalOffset == scrollViewer.ScrollableHeight)
        {
            command = GetCommand(listBox);

            // Execute the command
            command.Execute(listBox);
        }
    }
}

Example of using:

XAML

<Window.DataContext>
    <local:TestViewModel />
</Window.DataContext>

<Window.Resources>
    <x:Array x:Key="TestArray" Type="{x:Type sys:String}">
        <sys:String>Test1</sys:String>
        <sys:String>Test2</sys:String>
        <sys:String>Test3</sys:String>
        <sys:String>Test4</sys:String>
        <sys:String>Test5</sys:String>
        <sys:String>Test6</sys:String>
        <sys:String>Test7</sys:String>
        <sys:String>Test8</sys:String>
        <sys:String>Test9</sys:String>
        <sys:String>Test10</sys:String>
    </x:Array>
</Window.Resources>

<Grid>
    <ListBox Name="TestListBox"
             AttachedBehaviors:ScrollingToBottomBehavior.IsEnabled="True"
             AttachedBehaviors:ScrollingToBottomBehavior.Command="{Binding TestButtonCommand}"
             ItemsSource="{StaticResource TestArray}"
             Height="50" />
</Grid>

TestViewModel

public class TestViewModel
{
    private ICommand _testButtonCommand = null;

    public ICommand TestButtonCommand
    {
        get
        {
            if (_testButtonCommand == null)
            {
                _testButtonCommand = new RelayCommand(param => this.TestButton(), null);
            }

            return _testButtonCommand;
        }
    }

    private void TestButton()
    {
        MessageBox.Show("Test command execute");
    }
}

ScrollingToBottomBehavior

public class ScrollingToBottomBehavior
{
    #region Private Section

    private static ListBox listBox = null;
    private static ICommand command = null;

    #endregion

    #region IsEnabledProperty

    public static readonly DependencyProperty IsEnabledProperty;

    public static void SetIsEnabled(DependencyObject DepObject, string value)
    {
        DepObject.SetValue(IsEnabledProperty, value);
    }

    public static bool GetIsEnabled(DependencyObject DepObject)
    {
        return (bool)DepObject.GetValue(IsEnabledProperty);
    }

    #endregion

    #region CommandProperty

    public static readonly DependencyProperty CommandProperty;

    public static void SetCommand(DependencyObject DepObject, ICommand value)
    {
        DepObject.SetValue(CommandProperty, value);
    }

    public static ICommand GetCommand(DependencyObject DepObject)
    {
        return (ICommand)DepObject.GetValue(CommandProperty);
    }

    static ScrollingToBottomBehavior()
    {
        IsEnabledProperty = DependencyProperty.RegisterAttached("IsEnabled",
                                                            typeof(bool),
                                                            typeof(ScrollingToBottomBehavior),
                                                            new UIPropertyMetadata(false, IsFrontTurn));

        CommandProperty = DependencyProperty.RegisterAttached("Command",
                                                            typeof(ICommand),
                                                            typeof(ScrollingToBottomBehavior));
    }

    #endregion

    private static void IsFrontTurn(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        listBox = sender as ListBox;

        if (listBox == null)
        {
            return;
        }

        if (e.NewValue is bool && ((bool)e.NewValue) == true)
        {
            listBox.Loaded += new RoutedEventHandler(listBoxLoaded);
        }
        else 
        {
            listBox.Loaded -= new RoutedEventHandler(listBoxLoaded);
        }
    }

    private static void listBoxLoaded(object sender, RoutedEventArgs e)
    {
        var scrollViewer = GetFirstChildOfType<ScrollViewer>(listBox);

        if (scrollViewer != null)
        {
            scrollViewer.ScrollChanged += new ScrollChangedEventHandler(scrollViewerScrollChanged);
        }
    }

    #region GetFirstChildOfType

    private static T GetFirstChildOfType<T>(DependencyObject dependencyObject) where T : DependencyObject
    {
        if (dependencyObject == null)
        {
            return null;
        }

        for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
        {
            var child = VisualTreeHelper.GetChild(dependencyObject, i);

            var result = (child as T) ?? GetFirstChildOfType<T>(child);

            if (result != null)
            {
                return result;
            }
        }

        return null;
    }

    #endregion

    private static void scrollViewerScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        var scrollViewer = sender as ScrollViewer;

        if (scrollViewer != null)
        {
            if (scrollViewer.VerticalOffset == scrollViewer.ScrollableHeight)
            {
                command = GetCommand(listBox);
                command.Execute(listBox);
            }
        }
    }
}

Complete sample project is available here.

这篇关于MVVM WPF 中的 ListBox 滚动事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆