将UI操作委派给ViewModel以供执行

时间:2013-09-30 21:30:30

标签: c# wpf mvvm

我有ScrollViewer,其中包含ItemsSource。这些项绑定到ViewModel并按升序排序。允许用户将项添加到此列表中,但是,由于排序顺序,列表需要滚动到底部。根据我的发现,ScrollViewer没有锁定到底部"功能,但有一个ScrollToEnd方法可以完成我正在寻找的方法。

问题是,这些项目是在ViewModel中添加的,而ViewModel显然无法访问View以调用ScrollToEnd上的ScrollViewer方法。为了解决这个问题,我在ViewModel中声明了一个动作委托,如下所示:

public Action ScrollAction { get; set; }

在创建ViewModel时将其设置在View中:

viewModel.ScrollAction = () => scrollViewer.ScrollToEnd();

将项目添加到列表后,将在ViewModel中执行委托。即使这样可行,但对我来说这感觉有点笨拙,因为这种方式打破了ViewModel与View的隔离。有没有更好的方法来实现这一目标?

1 个答案:

答案 0 :(得分:1)

我还会为您的滚动查看器投票选择AttachedProperty。

我创建了以下附加属性,以使用布尔变量将scroll绑定到end。

public static class ScrollViewerBehavior
    {
        public static readonly DependencyProperty ScrollToRightEndProperty =
            DependencyProperty.RegisterAttached("ScrollToRightEnd", typeof (bool), typeof (ScrollViewerBehavior),
                                                new PropertyMetadata(false, OnScrollToRightEndPropertyChanged));

        public static bool GetScrollToRightEnd(DependencyObject obj)
        {
            return (bool) obj.GetValue(ScrollToRightEndProperty);
        }

        public static void SetScrollToRightEnd(DependencyObject obj, bool value)
        {
            obj.SetValue(ScrollToRightEndProperty, value);
        }

        private static void OnScrollToRightEndPropertyChanged(DependencyObject sender,
                                                              DependencyPropertyChangedEventArgs e)
        {
            var sv = sender as ScrollViewer;
            if (sv == null) return;

            if ((bool) e.NewValue)
            {
                sv.ScrollToRightEnd();
            }
            else
            {
                sv.ScrollToLeftEnd();
            }
        }
    }

您可以在XAML中使用此附加属性...

<ScrollViewer ... local:ScrollViewerBehavior.ScrollToRightEnd="{Binding IsScrolledToEnd}" ... />

或者,如果您想在问题中保存操作委托,可以在上面的OnScrollToRightEndPropertyChanged方法中执行以下操作。

.....
var viewModel = sv.DataContext as YourViewModel;
if (viewModel != null)
{
    viewModel.ScrollAction = () => sv.ScrollToRightEnd();
}
.....