Пользовательский интерфейс WPF зависает при пожаре - PullRequest
2 голосов
/ 19 сентября 2010

Я пытаюсь программно прокрутить ScrollViewer.Но мой пользовательский интерфейс зависает, как только происходит событие.Если я уберу цикл while, эта проблема исчезнет, ​​но тогда я не получу нужное мне поведение.

Я использую WPF 4.0

Вот код:

<Page
    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:System="clr-namespace:System;assembly=mscorlib" mc:Ignorable="d"
    x:Class="MyApp.Home"
    x:Name="HomePage"
    WindowTitle="Home"
    FlowDirection="LeftToRight" Foreground="{x:Null}" MinWidth="1100" MinHeight="629" Loaded="HomePage_Loaded" SizeChanged="HomePage_SizeChanged">

    <Grid x:Name="LayoutRoot">
        <TextBlock HorizontalAlignment="Right" Height="48.806" Margin="0,15,15,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="138.908" FontSize="34.667" FontFamily="/MyApp;component/Fonts/#Calibri" Text="featured." Foreground="#FF333333" d:IsLocked="True"/>
        <ScrollViewer Height="215" Margin="-20.648,67.806,-20.648,0" VerticalAlignment="Top" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Disabled" Name="FeaturedScroll" Width="1141.296">
            <ListView x:Name="FeaturedList" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Disabled">
                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
            </ListView>
        </ScrollViewer>
        <Rectangle x:Name="Left" Height="215" Width="77.129" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,68,0,0" MouseEnter="Left_MouseEnter" Cursor="Hand" Fill="#00000000" MouseLeave="Left_MouseLeave" />
        <Rectangle x:Name="Right" Height="215" Width="77.129" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,68,0,0" MouseEnter="Right_MouseEnter" Cursor="Hand" Fill="#00000000" MouseLeave="Right_MouseLeave" />
    </Grid>
</Page>

private void Left_MouseEnter(object sender, MouseEventArgs e) {
    ScrollLeft = true;

    while (ScrollLeft == true)
        FeaturedScroll.ScrollToHorizontalOffset(FeaturedScroll.HorizontalOffset - 1);
}

private void Right_MouseEnter(object sender, MouseEventArgs e) {
    ScrollRight = true;

    while (ScrollRight == true)
        FeaturedScroll.ScrollToHorizontalOffset(FeaturedScroll.HorizontalOffset + 1);
}

private void Left_MouseLeave(object sender, MouseEventArgs e) {
    ScrollLeft = false;
}

private void Right_MouseLeave(object sender, MouseEventArgs e) {
    ScrollRight = false;
}

Ответы [ 4 ]

2 голосов
/ 19 сентября 2010

Ваш код, похоже, ожидает, что события (Left_MouseLeave) сработают, пока еще выполняется другое событие (Left_MouseEnter)

Это не так, события обслуживаются одним потоком и не будут перекрываться.

Вам нужно будет перейти на алгоритм, который более ориентирован на события. Я не вижу MouseHover в WPF, поэтому вам нужно что-то еще.

2 голосов
/ 19 сентября 2010

Вы не можете выполнять прокрутку из другого потока, но вам это не нужно, потому что вы можете решить проблему с помощью простых изменений кода.

Как и все остальные, вы не можете получить событие выхода из мыши, покасобытие ввода мыши работает, вы должны изменить свой код так, чтобы событие ввода мыши немедленно возвращалось (кстати, все события должны возвращаться немедленно, в противном случае вы программируете - и в крайних случаях вся система перестает отвечать на запросы).

Вот два варианта, которые вы можете попробовать:

  1. Добавить DispatcherTimer в свой класс, прокрутить фиксированную сумму в событии Tick таймера, при вводе мыши вызвать таймер Start.метод, при отпускании мыши вызов Stop.

  2. Использовать анимацию, начать прокрутку с помощью DoubleAnimation при вводе мыши, остановить анимацию и проверить текущее значение при отпускании мыши

  3. Использовать RepeatButton, еслиВы прокручиваете фиксированное количество в событии RepeatButton Click, событие будет вызываться повторно, пока кнопка нажата (это немного меняет поведение, потому что вы должны нажимать кнопку, а не просто наводить курсор на нее).

Возможно, есть и много других опций, и ни одна из них не связана с многопоточностью (потому что многопоточное решение здесь не подойдет)

2 голосов
/ 19 сентября 2010

Ваш цикл будет повторяться бесконечно, так как нечего делать ScrollLeft или ScrollRight false. Поскольку цикл не завершается, обработчик событий никогда не завершается, и новые события не запускаются.

Я бы предложил использовать анимацию раскадровки для прокрутки, а затем исследовать состояние мыши, когда анимация завершится.

0 голосов
/ 19 сентября 2010

Вот окончательный код. Надеюсь, это кому-нибудь поможет:

public MySlider() {
    this.InitializeComponent();

    ScrollLeft = true;

    timer = new DispatcherTimer();
    timer.Interval = TimeSpan.FromMilliseconds(0.01);
    timer.Tick += new EventHandler(timer_Tick);
}

void timer_Tick(object sender, EventArgs e) {
    if (ScrollLeft) MyScrollViewer.ScrollToHorizontalOffset(MyScrollViewer.HorizontalOffset - 0.1);
    else MyScrollViewer.ScrollToHorizontalOffset(MyScrollViewer.HorizontalOffset + 0.1);
}

private void Left_MouseEnter(object sender, MouseEventArgs e) {
    ScrollLeft = true;

    timer.Start();
}

private void Right_MouseEnter(object sender, MouseEventArgs e) {
    ScrollLeft = false;

    timer.Start();
}

private void Left_MouseLeave(object sender, MouseEventArgs e) {
    timer.Stop();

    ScrollLeft = false;
}

private void Right_MouseLeave(object sender, MouseEventArgs e) {
    timer.Stop();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...