Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在MVVM中处理“ScrollViewer.ScrollChanged”事件?_C#_Wpf_Mvvm_Event Handling - Fatal编程技术网

C# 如何在MVVM中处理“ScrollViewer.ScrollChanged”事件?

C# 如何在MVVM中处理“ScrollViewer.ScrollChanged”事件?,c#,wpf,mvvm,event-handling,C#,Wpf,Mvvm,Event Handling,我已尝试处理路由事件ScrollViewer.ScrollChangedofDataGrid以明显的方式: <i:Interaction.Triggers> <i:EventTrigger EventName="ScrollViewer.ScrollChanged"> <ei:CallMethodAction MethodName="ScrollChangedHandler" TargetObject="{Binding}"/>

我已尝试处理路由事件
ScrollViewer.ScrollChanged
of
DataGrid
以明显的方式:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="ScrollViewer.ScrollChanged">
       <ei:CallMethodAction MethodName="ScrollChangedHandler" TargetObject="{Binding}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>
mvvmjoy
使用此类:

公共类RoutedEventTrigger:EventTriggerBase
{
RoutedEvent _RoutedEvent;
//为了简洁起见,代码省略了
}
基本上,我有两个问题:

  • 对于
    mvvmjaco
    xml名称空间,我应该使用什么类或库
  • 如何处理viewModel及其参数中的
    ScrollViewer.ScrollChanged
    事件

  • 我不知道
    mvvmjaco
    ,但我对第二个问题有一些提示。您不能直接从
    DataGrid
    ScrollChanged
    添加处理程序。您可以扩展
    DataGrid
    ,并在其中添加自定义事件。例如:

    public class ExtendedDataGrid : DataGrid
    {
        public event ScrollChangedEventHandler ScrollChanged;
    
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
    
            var scrollViewer = (ScrollViewer)GetTemplateChild("DG_ScrollViewer");
    
            scrollViewer.ScrollChanged += OnScrollChanged;
        }
    
        protected virtual void OnScrollChanged(ScrollChangedEventArgs e)
        {
            ScrollChangedEventHandler handler = ScrollChanged;
            if (handler != null)
            {
                handler(this, e);
            }
        }
    
        private void OnScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            OnScrollChanged(e);
        }
    }
    
    XAML:

  • 看起来mvvmjaco:CommandAction是从ViewModel调用命令的操作。您可以使用i:InvokeCommandAction作为替代

  • 您可以使用链接文章中的RoutedEventTrigger来处理scroll changed事件

  • XAML:

    
    
    ViewModel和stuff:

    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        ObservableCollection<DataItem> _dataItems = new ObservableCollection<DataItem>();
        public ObservableCollection<DataItem> DataItems { get { return _dataItems; } }
    
        private TestCommand _scrollCommand;
        public ICommand ScrollCommand { get { return _scrollCommand; } }
    
        public string ScrollData { get; set; }
    
        public MainWindowViewModel()
        {
            for (int i = 0; i < 100; i++)
            {
                _dataItems.Add(new DataItem() { Field1 = i.ToString(), Field2 = (i * 2).ToString(), Field3 = (i * 3).ToString() });
            }
    
            _scrollCommand = new TestCommand(OnScroll);
        }
    
        private void OnScroll(object param)
        {
            ScrollChangedEventArgs args = param as ScrollChangedEventArgs;
    
            if (args != null)
            {
                ScrollData = $"VerticalChange = {args.VerticalChange}; VerticalOffset = {args.VerticalOffset}";
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ScrollData)));
            }
        }
    }
    
    public class DataItem
    {
        public string Field1 { get; set; }
        public string Field2 { get; set; }
        public string Field3 { get; set; }
    
    }
    
    public class TestCommand : ICommand
    {
        private Action<object> _execute;
    
        public event EventHandler CanExecuteChanged;
    
        public TestCommand(Action<object> execute)
        {
            _execute = execute;
        }
    
        public bool CanExecute(object parameter)
        {
            return true;
        }
    
        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
    
    public类MainWindowViewModel:INotifyPropertyChanged
    {
    公共事件属性更改事件处理程序属性更改;
    ObservableCollection_dataItems=新的ObservableCollection();
    公共ObservableCollection数据项{get{return{U DataItems;}}
    私有TestCommand\u scroll命令;
    公共ICommand ScrollCommand{get{return}\u ScrollCommand;}}
    公共字符串ScrollData{get;set;}
    公共主窗口视图模型()
    {
    对于(int i=0;i<100;i++)
    {
    _添加(新数据项(){Field1=i.ToString(),Field2=(i*2.ToString(),Field3=(i*3.ToString()});
    }
    _scrollCommand=新的TestCommand(OnScroll);
    }
    私有void OnScroll(对象参数)
    {
    ScrollChangedEventArgs args=参数为ScrollChangedEventArgs;
    如果(args!=null)
    {
    ScrollData=$“VerticalChange={args.VerticalChange};VerticalOffset={args.VerticalOffset}”;
    PropertyChanged?.Invoke(这是新的propertychangedventargs(nameof(ScrollData));
    }
    }
    }
    公共类数据项
    {
    公共字符串字段1{get;set;}
    公共字符串字段2{get;set;}
    公共字符串字段3{get;set;}
    }
    公共类TestCommand:ICommand
    {
    私人行动——执行;
    公共事件处理程序CanExecuteChanged;
    公共测试命令(操作执行)
    {
    _执行=执行;
    }
    公共布尔CanExecute(对象参数)
    {
    返回true;
    }
    public void Execute(对象参数)
    {
    _执行(参数);
    }
    }
    
    文章中的RoutedEventTrigger:

    public class RoutedEventTrigger : EventTriggerBase<DependencyObject>
    {
        RoutedEvent _routedEvent;
    
        public RoutedEvent RoutedEvent
        {
            get { return _routedEvent; }
            set { _routedEvent = value; }
        }
    
        public RoutedEventTrigger()
        {
        }
        protected override void OnAttached()
        {
            Behavior behavior = base.AssociatedObject as Behavior;
            FrameworkElement associatedElement = base.AssociatedObject as FrameworkElement;
    
            if (behavior != null)
            {
                associatedElement = ((IAttachedObject)behavior).AssociatedObject as FrameworkElement;
            }
            if (associatedElement == null)
            {
                throw new ArgumentException("Routed Event trigger can only be associated to framework elements");
            }
            if (RoutedEvent != null)
            {
                associatedElement.AddHandler(RoutedEvent, new RoutedEventHandler(this.OnRoutedEvent));
            }
        }
        void OnRoutedEvent(object sender, RoutedEventArgs args)
        {
            base.OnEvent(args);
        }
        protected override string GetEventName()
        {
            return RoutedEvent.Name;
        }
    }
    
    公共类RoutedEventTrigger:EventTriggerBase
    {
    RoutedEvent _RoutedEvent;
    公共路由事件路由事件
    {
    获取{return\u routedEvent;}
    设置{u routedEvent=value;}
    }
    公共路由EventTrigger()
    {
    }
    受保护的覆盖无效附加()
    {
    行为=base.AssociatedObject作为行为;
    FrameworkElement associatedElement=base.AssociatedObject作为FrameworkElement;
    if(行为!=null)
    {
    associatedElement=((IAttachedObject)行为)。将AssociatedObject作为FrameworkElement;
    }
    if(associatedElement==null)
    {
    抛出新ArgumentException(“路由事件触发器只能与框架元素关联”);
    }
    if(RoutedEvent!=null)
    {
    associatedElement.AddHandler(RoutedEvent,new RoutedEventHandler(this.OnRoutedEvent));
    }
    }
    void OnRoutedEvent(对象发送方,RoutedEventArgs)
    {
    base.OnEvent(args);
    }
    受保护的重写字符串GetEventName()
    {
    返回routeEvent.Name;
    }
    }
    
    CustomCommandAction类,用于将参数传递给命令

    public sealed class CustomCommandAction : TriggerAction<DependencyObject>
    {
        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.Register("CommandParameter", typeof(object), typeof(CustomCommandAction), null);
    
        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
            "Command", typeof(ICommand), typeof(CustomCommandAction), null);
    
        public ICommand Command
        {
            get
            {
                return (ICommand)this.GetValue(CommandProperty);
            }
            set
            {
                this.SetValue(CommandProperty, value);
            }
        }
    
        public object CommandParameter
        {
            get
            {
                return this.GetValue(CommandParameterProperty);
            }
    
            set
            {
                this.SetValue(CommandParameterProperty, value);
            }
        }
    
        protected override void Invoke(object parameter)
        {
            if (this.AssociatedObject != null)
            {
                ICommand command = this.Command;
                if (command != null)
                {
                    if (this.CommandParameter != null)
                    {
                        if (command.CanExecute(this.CommandParameter))
                        {
                            command.Execute(this.CommandParameter);
                        }
                    }
                    else
                    {
                        if (command.CanExecute(parameter))
                        {
                            command.Execute(parameter);
                        }
                    }
                }
            }
        }
    }
    
    公共密封类CustomCommandAction:TriggerAction
    {
    public static readonly dependencProperty命令参数解释属性=
    Register(“CommandParameter”、typeof(object)、typeof(CustomCommandAction)、null);
    公共静态只读DependencyProperty CommandProperty=DependencyProperty.Register(
    “命令”、typeof(ICommand)、typeof(CustomCommandAction)、null;
    公共ICommand命令
    {
    得到
    {
    返回(ICommand)this.GetValue(CommandProperty);
    }
    设置
    {
    this.SetValue(CommandProperty,value);
    }
    }
    公共对象命令参数
    {
    得到
    {
    返回此.GetValue(CommandParameterProperty);
    }
    设置
    {
    this.SetValue(CommandParameterProperty,value);
    }
    }
    受保护的覆盖无效调用(对象参数)
    {
    if(this.AssociatedObject!=null)
    {
    ICommand命令=此.command;
    if(命令!=null)
    {
    if(this.CommandParameter!=null)
    {
    if(command.CanExecute(this.CommandParameter))
    {
    command.Execute(此.CommandParameter);
    }
    }
    其他的
    {
    if(command.CanExecute(参数))
    {
    command.Execute(参数);
    }
    }
    }
    }
    }
    }
    
    我将使用以下附加属性解决此问题:

    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    namespace WpfApplication2
    {
        public class DataGridExtensions
        {
            public static readonly DependencyProperty ScrollChangedCommandProperty = DependencyProperty.RegisterAttached(
                "ScrollChangedCommand", typeof(ICommand), typeof(DataGridExtensions),
                new PropertyMetadata(default(ICommand), OnScrollChangedCommandChanged));
    
            private static void OnScrollChangedCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                DataGrid dataGrid = d as DataGrid;
                if (dataGrid == null)
                    return;
                if (e.NewValue != null)
                {
                    dataGrid.Loaded += DataGridOnLoaded;
                }
                else if (e.OldValue != null)
                {
                    dataGrid.Loaded -= DataGridOnLoaded;
                }
            }
    
            private static void DataGridOnLoaded(object sender, RoutedEventArgs routedEventArgs)
            {
                DataGrid dataGrid = sender as DataGrid;
                if (dataGrid == null)
                    return;
    
                ScrollViewer scrollViewer = UIHelper.FindChildren<ScrollViewer>(dataGrid).FirstOrDefault();
                if (scrollViewer != null)
                {
                    scrollViewer.ScrollChanged += ScrollViewerOnScrollChanged;
                }
            }
    
            private static void ScrollViewerOnScrollChanged(object sender, ScrollChangedEventArgs e)
            {
                DataGrid dataGrid = UIHelper.FindParent<DataGrid>(sender as ScrollViewer);
                if (dataGrid != null)
                {
                    ICommand command = GetScrollChangedCommand(dataGrid);
                    command.Execute(e);
                }
            }
    
            public static void SetScrollChangedCommand(DependencyObject element, ICommand value)
            {
                element.SetValue(ScrollChangedCommandProperty, value);
            }
    
            public static ICommand GetScrollChangedCommand(DependencyObject element)
            {
                return (ICommand)element.GetValue(ScrollChangedCommandProperty);
            }
        }
    }
    
    然后,您可以在
    数据网格的定义中写入:

    <DataGrid ItemsSource="{Binding MySource}" extensionsNamespace:DataGridExtensions.ScrollChangedCommand="{Binding ScrollCommand}"/>
    
    关于您的第一个问题(特别感谢):

    MVVMJaco
    是xmlns:MVVMJaco=“galasoft.ch/mvvmlight” 所需的图书馆包括:

      public class MainWindowViewModel : INotifyPropertyChanged
      {
          public event PropertyChangedEventHandler PropertyChanged;
      
          ObservableCollection<DataItem> _dataItems = new ObservableCollection<DataItem>();
          public ObservableCollection<DataItem> DataItems { get { return _dataItems; } }
      
          private TestCommand _scrollCommand;
          public ICommand ScrollCommand { get { return _scrollCommand; } }
      
          public string ScrollData { get; set; }
      
          public MainWindowViewModel()
          {
              for (int i = 0; i < 100; i++)
              {
                  _dataItems.Add(new DataItem() { Field1 = i.ToString(), Field2 = (i * 2).ToString(), Field3 = (i * 3).ToString() });
              }
      
              _scrollCommand = new TestCommand(OnScroll);
          }
      
          private void OnScroll(object param)
          {
              ScrollChangedEventArgs args = param as ScrollChangedEventArgs;
      
              if (args != null)
              {
                  ScrollData = $"VerticalChange = {args.VerticalChange}; VerticalOffset = {args.VerticalOffset}";
                  PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ScrollData)));
              }
          }
      }
      
      public class DataItem
      {
          public string Field1 { get; set; }
          public string Field2 { get; set; }
          public string Field3 { get; set; }
      
      }
      
      public class TestCommand : ICommand
      {
          private Action<object> _execute;
      
          public event EventHandler CanExecuteChanged;
      
          public TestCommand(Action<object> execute)
          {
              _execute = execute;
          }
      
          public bool CanExecute(object parameter)
          {
              return true;
          }
      
          public void Execute(object parameter)
          {
              _execute(parameter);
          }
      }
      
      public class RoutedEventTrigger : EventTriggerBase<DependencyObject>
      {
          RoutedEvent _routedEvent;
      
          public RoutedEvent RoutedEvent
          {
              get { return _routedEvent; }
              set { _routedEvent = value; }
          }
      
          public RoutedEventTrigger()
          {
          }
          protected override void OnAttached()
          {
              Behavior behavior = base.AssociatedObject as Behavior;
              FrameworkElement associatedElement = base.AssociatedObject as FrameworkElement;
      
              if (behavior != null)
              {
                  associatedElement = ((IAttachedObject)behavior).AssociatedObject as FrameworkElement;
              }
              if (associatedElement == null)
              {
                  throw new ArgumentException("Routed Event trigger can only be associated to framework elements");
              }
              if (RoutedEvent != null)
              {
                  associatedElement.AddHandler(RoutedEvent, new RoutedEventHandler(this.OnRoutedEvent));
              }
          }
          void OnRoutedEvent(object sender, RoutedEventArgs args)
          {
              base.OnEvent(args);
          }
          protected override string GetEventName()
          {
              return RoutedEvent.Name;
          }
      }
      
      public sealed class CustomCommandAction : TriggerAction<DependencyObject>
      {
          public static readonly DependencyProperty CommandParameterProperty =
              DependencyProperty.Register("CommandParameter", typeof(object), typeof(CustomCommandAction), null);
      
          public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
              "Command", typeof(ICommand), typeof(CustomCommandAction), null);
      
          public ICommand Command
          {
              get
              {
                  return (ICommand)this.GetValue(CommandProperty);
              }
              set
              {
                  this.SetValue(CommandProperty, value);
              }
          }
      
          public object CommandParameter
          {
              get
              {
                  return this.GetValue(CommandParameterProperty);
              }
      
              set
              {
                  this.SetValue(CommandParameterProperty, value);
              }
          }
      
          protected override void Invoke(object parameter)
          {
              if (this.AssociatedObject != null)
              {
                  ICommand command = this.Command;
                  if (command != null)
                  {
                      if (this.CommandParameter != null)
                      {
                          if (command.CanExecute(this.CommandParameter))
                          {
                              command.Execute(this.CommandParameter);
                          }
                      }
                      else
                      {
                          if (command.CanExecute(parameter))
                          {
                              command.Execute(parameter);
                          }
                      }
                  }
              }
          }
      }
      
      using System.Linq;
      using System.Windows;
      using System.Windows.Controls;
      using System.Windows.Input;
      
      namespace WpfApplication2
      {
          public class DataGridExtensions
          {
              public static readonly DependencyProperty ScrollChangedCommandProperty = DependencyProperty.RegisterAttached(
                  "ScrollChangedCommand", typeof(ICommand), typeof(DataGridExtensions),
                  new PropertyMetadata(default(ICommand), OnScrollChangedCommandChanged));
      
              private static void OnScrollChangedCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
              {
                  DataGrid dataGrid = d as DataGrid;
                  if (dataGrid == null)
                      return;
                  if (e.NewValue != null)
                  {
                      dataGrid.Loaded += DataGridOnLoaded;
                  }
                  else if (e.OldValue != null)
                  {
                      dataGrid.Loaded -= DataGridOnLoaded;
                  }
              }
      
              private static void DataGridOnLoaded(object sender, RoutedEventArgs routedEventArgs)
              {
                  DataGrid dataGrid = sender as DataGrid;
                  if (dataGrid == null)
                      return;
      
                  ScrollViewer scrollViewer = UIHelper.FindChildren<ScrollViewer>(dataGrid).FirstOrDefault();
                  if (scrollViewer != null)
                  {
                      scrollViewer.ScrollChanged += ScrollViewerOnScrollChanged;
                  }
              }
      
              private static void ScrollViewerOnScrollChanged(object sender, ScrollChangedEventArgs e)
              {
                  DataGrid dataGrid = UIHelper.FindParent<DataGrid>(sender as ScrollViewer);
                  if (dataGrid != null)
                  {
                      ICommand command = GetScrollChangedCommand(dataGrid);
                      command.Execute(e);
                  }
              }
      
              public static void SetScrollChangedCommand(DependencyObject element, ICommand value)
              {
                  element.SetValue(ScrollChangedCommandProperty, value);
              }
      
              public static ICommand GetScrollChangedCommand(DependencyObject element)
              {
                  return (ICommand)element.GetValue(ScrollChangedCommandProperty);
              }
          }
      }
      
      using System.Collections.Generic;
      using System.Windows;
      using System.Windows.Media;
      
      namespace WpfApplication2
      {
          internal static class UIHelper
          {
              internal static IList<T> FindChildren<T>(DependencyObject element) where T : FrameworkElement
              {
                  List<T> retval = new List<T>();
                  for (int counter = 0; counter < VisualTreeHelper.GetChildrenCount(element); counter++)
                  {
                      FrameworkElement toadd = VisualTreeHelper.GetChild(element, counter) as FrameworkElement;
                      if (toadd != null)
                      {
                          T correctlyTyped = toadd as T;
                          if (correctlyTyped != null)
                          {
                              retval.Add(correctlyTyped);
                          }
                          else
                          {
                              retval.AddRange(FindChildren<T>(toadd));
                          }
                      }
                  }
                  return retval;
              }
      
              internal static T FindParent<T>(DependencyObject element) where T : FrameworkElement
              {
                  FrameworkElement parent = VisualTreeHelper.GetParent(element) as FrameworkElement;
                  while (parent != null)
                  {
                      T correctlyTyped = parent as T;
                      if (correctlyTyped != null)
                      {
                          return correctlyTyped;
                      }
                      return FindParent<T>(parent);
                  }
                  return null;
              }
          }
      }
      
      <DataGrid ItemsSource="{Binding MySource}" extensionsNamespace:DataGridExtensions.ScrollChangedCommand="{Binding ScrollCommand}"/>
      
      private ICommand scrollCommand;
      public ICommand ScrollCommand
      {
          get { return scrollCommand ?? (scrollCommand = new RelayCommand(Scroll)); }
      }
      
      private void Scroll(object parameter)
      {
          ScrollChangedEventArgs scrollChangedEventArgs = parameter as ScrollChangedEventArgs;
          if (scrollChangedEventArgs != null)
          {
      
          }
      }