user1654278 user1654278 - 9 days ago 5
C# Question

Scroll grid with buttons- how to prevent button elements from firing while scrolling

I have an app in wpf using caliburn micro framework with mvvm pattern which is running in kiosk with touch screen. i want to scroll buttons and when the user wants to click them. I have made grid scrollable inside a scroll viewer but the proplem is that when I leave the touch, it's raising the button-click event.
Here's the code (xaml) :

<ScrollViewer VerticalScrollBarVisibility="Hidden" x:Name="scroller">
<Grid ScrollViewer.CanContentScroll="True">

<Grid.RowDefinitions>
<RowDefinition Height="15"/>
<RowDefinition x:Name="Row1"/>
<RowDefinition Height="15"/>
<RowDefinition x:Name="Row2"/>
<RowDefinition Height="15"/>
<RowDefinition x:Name="Row3"/>
<RowDefinition Height="15"/>
<RowDefinition x:Name="Row4"/>
<RowDefinition Height="15"/>
<RowDefinition x:Name="Row5"/>
<RowDefinition Height="15"/>
<RowDefinition x:Name="Row6"/>
<RowDefinition Height="15"/>
<RowDefinition x:Name="Row7"/>
<RowDefinition Height="15"/>
<RowDefinition x:Name="Row8"/>
</Grid.RowDefinitions>

<Button x:Name="ViewRedirect1" Grid.Row="1">
<Image Source="{Binding Path=LeftImage1}" Stretch="UniformToFill"/>
</Button>
<Button x:Name="ViewRedirect2" Grid.Row="3">
<Image Source="{Binding Path=LeftImage2}" Stretch="UniformToFill"/>
</Button>
<Button x:Name="ViewRedirect3" Grid.Row="5">
<Image Source="{Binding Path=LeftImage3}" Stretch="UniformToFill"/>
</Button>
<Button x:Name="ViewRedirect4" Grid.Row="7">
<Image Source="{Binding Path=LeftImage4}" Stretch="UniformToFill"/>
</Button>
<Button x:Name="ViewRedirect5" Grid.Row="9">
<Image Source="{Binding Path=LeftImage5}" Stretch="UniformToFill"/>
</Button>
<Button x:Name="ViewRedirect6" Grid.Row="11">
<Image Source="{Binding Path=LeftImage6}" Stretch="UniformToFill"/>
</Button>
<Button x:Name="ViewRedirect7" Grid.Row="13">
<Image Source="{Binding Path=LeftImage7}" Stretch="UniformToFill"/>
</Button>
<Button x:Name="ViewRedirect8" Grid.Row="15">
<Image Source="{Binding Path=LeftImage8}" Stretch="UniformToFill"/>
</Button>

</Grid>
</ScrollViewer>


and here is the behind code about the events

private Point scrollStartPoint;

private Point scrollStartOffset;
private DateTime mouseTimer;
private void Scroller_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
mouseTimer = DateTime.Now;

ScrollViewer scrollViewer = sender as ScrollViewer;
if (scrollViewer.IsMouseOver)
{
scrollStartPoint = e.GetPosition(scrollViewer);
scrollStartOffset.X = scrollViewer.HorizontalOffset;
scrollStartOffset.Y = scrollViewer.VerticalOffset;
}

}

private void Scroller_PreviewMouseMove(object sender, MouseEventArgs e)
{
ScrollViewer scrollViewer = sender as ScrollViewer;

if (scrollViewer.IsMouseOver)
{
Point currentPoint = e.GetPosition(scrollViewer);

Point delta = new Point(scrollStartPoint.X - currentPoint.X,
scrollStartPoint.Y - currentPoint.Y);

scrollTarget.X = scrollStartOffset.X + delta.X;
scrollTarget.Y = scrollStartOffset.Y + delta.Y;

scrollViewer.ScrollToHorizontalOffset(scrollTarget.X);
scrollViewer.ScrollToVerticalOffset(scrollTarget.Y);

}
}

private void Scroller_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
ScrollViewer scrollViewer = sender as ScrollViewer;
if (scrollViewer.IsMouseCaptured) {
scrollViewer.ReleaseMouseCapture();
}
TimeSpan difference = DateTime.Now - mouseTimer;
if (difference.TotalMilliseconds>500)
{
e.Handled = true;
}
}


the scroll is goog but when in the button that I leave the finger up, this makes the redirecting

updated code based on answer below

Answer

You can implement various solutions for this problem,

Look at my answer here, or the authors answer for two separate ways to do it,

WPF Click Button Scrollviewer

The solution is with a left mouse click button, but can be adapted for touch,

my way was to use DateTime, to calculate how much time you press, if you are just touching a button, then it would be less than 1second touch, if you are scrolling it would be more than 1 second, so it doesn't raise the button click event

private DateTime mouseTimer;

private void Scroller_PreviewTouchDown(object sender, TouchEventArgs e)
    {
        mouseTimer = DateTime.Now;
        ScrollViewer scrollViewer = sender as ScrollViewer;
        if (scrollViewer.IsMouseOver)
        {
            scrollStartPoint = e.GetTouchPoint(scrollViewer).Position; 
            scrollStartOffset.X = scrollViewer.HorizontalOffset;
            scrollStartOffset.Y = scrollViewer.VerticalOffset;
        }

    }
private void Scroller_PreviewTouchUp(object sender, TouchEventArgs e)
    {

        ScrollViewer scrollViewer = sender as ScrollViewer;
        if(scrollViewer.IsMouseCaptured)
        {
            scrollViewer.ReleaseAllTouchCaptures();
        }

        TimeSpan difference = DateTime.Now - mouseTimer;

              if (difference.TotalSeconds < 1)
               {
                btn_Click(sender, e); //button you want or don't want to rise event
               }
              else
              return;

    }

UPDATE

Second solution, go to the answer I posted above and use the c# code in the second answer, it is more robust