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
ofDataGrid
以明显的方式:
<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名称空间,我应该使用什么类或库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:
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)
{
}
}