Вложенные ScrollViewers в WPF с различными PanningModes?

Я попробовал все предложения, найденные здесь, начиная с включения менее безопасных приложений, до пробного порта 587 ... ничего не получилось. Наконец, я просто прокомментировал строку UseDefaultCredentials = false. Все работало, если я не касался этого логического.

7
задан josh2112 13 July 2018 в 16:06
поделиться

1 ответ

У меня есть решение для вас с небольшой ошибкой. Чтобы переключить PanningMode, вам необходимо нажать «Вверх». Возможно, вы можете найти ошибку, которая работает без «Touch Up» еще раз.


После изменения PanningMode родительского ScrollViewer события Touch больше не были перенаправлены внутреннему ребенку ScrollViewer. Поэтому я также попытался перенаправить события касания на родителя ScrollViewer. Возможно, у меня есть только ошибка в моей логике.

<ScrollViewer x:Name="Daddy" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled" PanningMode="HorizontalOnly">
        <ItemsControl ItemsSource="{Binding Columns}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" PanningMode="VerticalOnly">
                        <ItemsControl ItemsSource="{Binding Rows}">
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Rectangle Width="300" Height="100" Fill="Purple" Margin="20"/>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                        <i:Interaction.Behaviors>
                            <local:BubbleTouch ParentElement="{Binding ElementName=Daddy}"/>
                        </i:Interaction.Behaviors>
                    </ScrollViewer>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </ScrollViewer>

public class BubbleTouch : Behavior<ScrollViewer>
{
    public ScrollViewer ParentElement
    {
        get => (ScrollViewer) GetValue(ParentElementProperty);
        set => SetValue(ParentElementProperty, value);
    }

    /// <summary>
    /// The <see cref="ParentElement"/> DependencyProperty.
    /// </summary>
    public static readonly DependencyProperty ParentElementProperty = DependencyProperty.Register("ParentElement", typeof(ScrollViewer), typeof(BubbleTouch), new PropertyMetadata(null));

    private Brush _DefaultBrush;

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.TouchMove += _ChildMove;
        AssociatedObject.TouchDown += _ChildDown;
        AssociatedObject.TouchUp += _ChildUp;
        ParentElement.TouchMove += _ParentMove;
        ParentElement.TouchDown += _ParentDown;
        ParentElement.TouchUp += _ParentUp;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.TouchMove -= _ChildMove;
        AssociatedObject.TouchDown -= _ChildDown;
        AssociatedObject.TouchUp -= _ChildUp;
        base.OnDetaching();
    }

    private TouchPoint _ParentStartPosition;
    private bool _ParentTouchDown;
    private bool _ParentMoving;

    private void _ParentDown(object sender, TouchEventArgs e)
    {
        _ParentTouchDown = true;
        _ParentStartPosition = e.GetTouchPoint(Application.Current.MainWindow);
    }

    private void _ParentMove(object sender, TouchEventArgs e)
    {
        if (_ParentTouchDown && !_ParentMoving)
        {
            double deltaX = _ParentStartPosition.Bounds.X - e.GetTouchPoint(Application.Current.MainWindow).Bounds.X;
            double deltaY = _ParentStartPosition.Bounds.Y - e.GetTouchPoint(Application.Current.MainWindow).Bounds.Y;

            Trace.WriteLine($"{deltaX} | {deltaY}");

            if (deltaX > deltaY && deltaX > 5)
            {
                AssociatedObject.PanningMode = PanningMode.None;
                AssociatedObject.Background = Brushes.Aqua;
                ParentElement.PanningMode = PanningMode.HorizontalOnly;
                _ParentMoving = true;
            }
            else if (deltaY > deltaX && deltaY > 5)
            {
                AssociatedObject.PanningMode = PanningMode.VerticalOnly;
                AssociatedObject.Background = Brushes.ForestGreen;
                ParentElement.PanningMode = PanningMode.HorizontalOnly;
                _ParentMoving = true;
            }
        }
    }

    private void _ParentUp(object sender, TouchEventArgs e)
    {
        _ParentTouchDown = false;
        _ParentMoving = false;
        AssociatedObject.Background = _DefaultBrush;
    }

    private TouchPoint _ChildStartPosition;
    private bool _ChildTouchDown;
    private bool _ChildMoving;

    private void _ChildDown(object sender, TouchEventArgs e)
    {
        _DefaultBrush = AssociatedObject.Background;
        _ChildTouchDown = true;
        _ChildStartPosition = e.GetTouchPoint(Application.Current.MainWindow);
    }

    private void _ChildMove(object sender, TouchEventArgs e)
    {
        if (_ChildTouchDown && !_ChildMoving)
        {
            double deltaX = _ChildStartPosition.Bounds.X - e.GetTouchPoint(Application.Current.MainWindow).Bounds.X;
            double deltaY = _ChildStartPosition.Bounds.Y - e.GetTouchPoint(Application.Current.MainWindow).Bounds.Y;

            Trace.WriteLine($"{deltaX} | {deltaY}");

            if (deltaX > deltaY && deltaX > 5)
            {
                AssociatedObject.PanningMode = PanningMode.None;
                AssociatedObject.Background = Brushes.Aqua;
                ParentElement.PanningMode = PanningMode.HorizontalOnly;
                _ChildMoving = true;
            }
            else if (deltaY > deltaX && deltaY > 5)
            {
                AssociatedObject.PanningMode = PanningMode.VerticalOnly;
                AssociatedObject.Background = Brushes.ForestGreen;
                ParentElement.PanningMode = PanningMode.HorizontalOnly;
                _ChildMoving = true;
            }
        }

        if (AssociatedObject.PanningMode == PanningMode.None)
        {
            e.Handled = true;
        }
    }

    private void _ChildUp(object sender, TouchEventArgs e)
    {
        AssociatedObject.Background = _DefaultBrush;
        _ChildTouchDown = false;
        _ChildMoving = false;
    }
}

Предварительный просмотр

0
ответ дан Dominic Jonas 17 August 2018 в 12:26
поделиться
  • 1
    Спасибо за ответ @Dominic, но я не получил этого. AssociatedObject.RaiseEvent () просто приводит к StackOverflow, поскольку поведение постоянно перенаправляет событие обратно на тот же элемент управления. Выполнение изменения для отправки события родителю избавилось от исключения, но сделало все окно неактуальным, чтобы коснуться событий. Кроме того, пузырь событий от ItemsControl до родительского ScrollViewer - разве это не так? – josh2112 20 July 2018 в 19:51
  • 2
    Я также подумал, что вы пытаетесь сделать, это пузырь сенсорных событий от дочернего внутреннего ScrollViewer к внешнему ScrollViewer, и в этом случае поведение должно быть на один уровень выше с ItemsControl. Но это не работает, поскольку внутренний ScrollViewer / ItemsControl является DataTemplate, поэтому он не имеет визуального родителя. – josh2112 20 July 2018 в 19:52
  • 3
    @ josh2112 Я обновил свой ответ! – Dominic Jonas 23 July 2018 в 14:02
  • 4
    Meh ... Мне это не нравится ... он чувствует себя взломанным, и трудно заставить горизонтальный scrollviewer активировать ... но он отвечает на вопрос, поэтому я награждаю вас щедростью. – josh2112 24 July 2018 в 17:32
  • 5
    Спасибо, но я не ожидал, что вы их примете. Меня все еще интересует лучшее решение и опубликует его, как только я его найду! – Dominic Jonas 25 July 2018 в 06:41
Другие вопросы по тегам:

Похожие вопросы: