我试图以明显的方式处理ScrollViewer.ScrollChanged
的路由事件DataGrid
:
<i:Interaction.Triggers>
<i:EventTrigger EventName="ScrollViewer.ScrollChanged">
<ei:CallMethodAction MethodName="ScrollChangedHandler" TargetObject="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
但ScrollChangedHandler
甚至没有被解雇。
然后,我找到了this article about handling events,但我无法弄清楚xmlns
使用了什么xml命名空间(mvvmjaco
):
<Image Width="360" Height="177" Source="Resources\PlayerArea.png">
<i:Interaction.Triggers>
<mvvmjoy:RoutedEventTrigger RoutedEvent="s:Contacts.ContactDown">
<mvvmjaco:CommandAction Command="{Binding TouchCommand}" />
</mvvmjoy:RoutedEventTrigger>
</i:Interaction.Triggers>
</Image>
mvvmjoy
使用此课程from the article:
public class RoutedEventTrigger :EventTriggerBase<DependencyObject>
{
RoutedEvent _routedEvent;
//The code omitted for the brevity
}
基本上,我有两个问题:
mvvmjaco
xml命名空间使用哪个类或库?ScrollViewer.ScrollChanged
事件?答案 0 :(得分:3)
我会用以下的附属物来解决它:
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);
}
}
}
班级UIHelper
如下:
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
:
<DataGrid ItemsSource="{Binding MySource}" extensionsNamespace:DataGridExtensions.ScrollChangedCommand="{Binding ScrollCommand}"/>
在您的ViewModel中,您有一个ICommand
,如下所示:
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)
{
}
}
第一个问题(特别感谢Andy ONeill and Magnus Montin):
MVVMJaco
是xmlns:mvvmjaco =&#34; galasoft.ch/mvvmlight"
所需的库是:
答案 1 :(得分:2)
似乎mvvmjaco:CommandAction是一个从ViewModel调用命令的操作。您可以使用i:InvokeCommandAction作为替代。
您可以使用已链接的文章中的RoutedEventTrigger来处理滚动已更改的事件。
XAML:
<Window x:Class="ScrollChangedTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ScrollChangedTest"
mc:Ignorable="d"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<DataGrid ItemsSource="{Binding DataItems}" AutoGenerateColumns="True">
<i:Interaction.Triggers>
<local:RoutedEventTrigger RoutedEvent="ScrollViewer.ScrollChanged">
<local:CustomCommandAction Command="{Binding ScrollCommand}" />
</local:RoutedEventTrigger>
</i:Interaction.Triggers>
</DataGrid>
<TextBlock Grid.Row="1" Text="{Binding ScrollData}" />
</Grid>
</Window>
ViewModel&amp;东西:
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);
}
}
文章中的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;
}
}
CustomCommandAction类,用于将args传递给命令
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);
}
}
}
}
}
}
答案 2 :(得分:1)
我不知道mvvmjaco
但我对第二个问题有一些暗示。您无法直接从ScrollChanged
向DataGrid
添加处理程序。您可以扩展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:
<local:ExtendedDataGrid>
<i:Interaction.Triggers>
<i:EventTrigger EventName="ScrollChanged">
<ei:CallMethodAction TargetObject="{Binding}"
MethodName="OnScrollChanged" />
</i:EventTrigger>
</i:Interaction.Triggers>
</local:ExtendedDataGrid>
处理程序:
public void OnScrollChanged(object sender, ScrollChangedEventArgs e)
{
}