Lamloumi Afif
Lamloumi Afif

Reputation: 9081

Firing scrollchanged event in wpf application

I had this code

View

    <DataGrid x:Name="dgFactures" ScrollViewer.VerticalScrollBarVisibility="Auto"  Width="auto">
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="ScrollChanged">
                                    <cmd:EventToCommand Command="{Binding ScrollChangedCommand}" PassEventArgsToCommand="True"></cmd:EventToCommand>
                                </i:EventTrigger>
                             </i:Interaction.Triggers>
              <DataGrid.Columns>
                        <DataGridTemplateColumn Header="Hébergement">
                                    <DataGridTemplateColumn.CellTemplate>
                                        <DataTemplate>
                                            <CheckBox IsChecked="{Binding Hebergement,  Converter={StaticResource NullToFalse}}">
                                                <i:Interaction.Triggers>
                                                    <i:EventTrigger EventName="Checked">
                                                        <cmd:EventToCommand Command="{Binding HebergementCommand}" PassEventArgsToCommand="True"></cmd:EventToCommand>
                                                    </i:EventTrigger>
                                                    <i:EventTrigger EventName="Unchecked">
                                                        <cmd:EventToCommand Command="{Binding HebergementCommand}" PassEventArgsToCommand="True"></cmd:EventToCommand>
                                                    </i:EventTrigger>
                                                </i:Interaction.Triggers>

                                            </CheckBox>
                                        </DataTemplate>
                                    </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
          </DataGrid.Columns>
</DataGrid>

ViewModel

 public RelayCommand<RoutedEventArgs> HebergementCommand { get; set; }
 public RelayCommand<ScrollChangedEventArgs> ScrollChangedCommand { get; set; }
  HebergementCommand = new RelayCommand<RoutedEventArgs>((e) =>
            {
                PropertyInfo IsChekedInfo = e.Source.GetType().GetProperty("IsChecked");
                bool isChecked = (bool)IsChekedInfo.GetValue(e.Source, null);
                Hebergement = isChecked;
            });

            ScrollChangedCommand = new RelayCommand<ScrollChangedEventArgs>((e) =>
            {
                if (e.HorizontalChange != 0)
                {
                    // Do stuff..
                }
            });

The problem is :

I need to know:

  1. Why this happens?
  2. How can I fix it?

Thanks

Upvotes: 1

Views: 1678

Answers (1)

Il Vic
Il Vic

Reputation: 5666

Your issue is caused by the way that EventTriggerBase works. If you take a look to its code you can see this:

private void RegisterEvent(object obj, string eventName)
{
    Type type = obj.GetType();
    EventInfo @event = type.GetEvent(eventName);
    if (@event == null)
    {
        if (this.SourceObject != null)
        {
            throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, ExceptionStringTable.EventTriggerCannotFindEventNameExceptionMessage, new object[]
            {
                eventName,
                obj.GetType().Name
            }));
        }
        return;
    }
    /* and so on... */
}

However the point is that it uses reflection to find the event which will be triggered. So it cannot find attached events attached to a FrameworkElement (in your case the DataGrid).

For fixing this issue, write your own EventTrigger:

public class AttachedEventTrigger : EventTriggerBase<DependencyObject>
{
    public RoutedEvent RoutedEvent { get; set; }

    private FrameworkElement AssociatedElement
    {
        get
        {
            IAttachedObject attachedObject = AssociatedObject as IAttachedObject;
            FrameworkElement associatedElement = AssociatedObject as FrameworkElement;

            if (attachedObject != null)
            {
                associatedElement = attachedObject.AssociatedObject as FrameworkElement;
            }

            return associatedElement;
        }
    }

    protected override void OnAttached()
    {
        FrameworkElement associatedElement = AssociatedElement;

        if (associatedElement == null)
        {
            throw new InvalidOperationException();
        }

        if (RoutedEvent != null)
        {
            associatedElement.AddHandler(RoutedEvent, new RoutedEventHandler(OnRoutedEvent));
        }
    }

    protected override void OnDetaching()
    {
        FrameworkElement associatedElement = AssociatedElement;

        if (RoutedEvent != null)
        {
            associatedElement.RemoveHandler(RoutedEvent, new RoutedEventHandler(OnRoutedEvent));
        }
    }

    private void OnRoutedEvent(object sender, RoutedEventArgs args)
    {
        OnEvent(args);
    }

    protected override string GetEventName()
    {
        if (RoutedEvent != null)
        {
            return RoutedEvent.Name;
        }

        return String.Empty;
    }
}

You can use it in this way:

<DataGrid x:Name="dgFactures" ScrollViewer.VerticalScrollBarVisibility="Auto" Width="auto">
    <i:Interaction.Triggers>
        <local:AttachedEventTrigger RoutedEvent="ScrollViewer.ScrollChanged">
            <!-- your actions -->
        </local:AttachedEventTrigger>
    </i:Interaction.Triggers>
    <DataGrid.Columns>
        <!-- your columns -->
    </DataGrid.Columns>
</DataGrid>

I hope this sample can help you.

Upvotes: 2

Related Questions