Попытка программно прокрутить просмотрщик - PullRequest
4 голосов
/ 24 марта 2012

Я разрабатываю приложение WPF, в котором у меня есть ScrollViewer с сеткой (16 ColumnDefinitions all auto width) с изображением, назначенным каждому столбцу.Эффект, который я хочу создать, заключается в том, что когда мышь входит в область слева от ScrollViewer, изображения прокручиваются влево ... и когда мышь входит в область справа от ScrollViewer, они прокручиваются вправо.Полосы прокрутки будут скрыты.Области слева и справа определяются двумя прямоугольниками с событиями mouseEnter и mouseLeave.Мой код использует таймер для программной прокрутки ScrollViewer влево или вправо.

Вот мой код ...

Imports System
Imports System.IO
Imports System.Net
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Data
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.Windows.Navigation


Partial Public Class Crime

    Dim ScrollLeft As Boolean = True
    Dim atimer As New System.Timers.Timer()

    Public Sub New()
        MyBase.New()

        Me.InitializeComponent()

        ' Insert code required on object creation below this point.

        ' Hook up the Elapsed event for the timer.
        AddHandler atimer.Elapsed, AddressOf Me.timer_Tick

        atimer.Interval = 100
        atimer.Enabled = True

    End Sub

    'CODE TO SCROLL SCROLLVIEWER PROGRAMATICALLY
    Private Sub timer_Tick(sender As Object, e As EventArgs)
        If ScrollLeft Then
            svImages.ScrollToHorizontalOffset(svImages.HorizontalOffset - 1)
        Else
            svImages.ScrollToHorizontalOffset(svImages.HorizontalOffset + 1)
        End If
    End Sub

    Private Sub Left_MouseEnter(sender As Object, e As MouseEventArgs)
        ScrollLeft = True
        atimer.Start()
    End Sub

    Private Sub Right_MouseEnter(sender As Object, e As MouseEventArgs)
        ScrollLeft = False
        atimer.Start()
    End Sub

    Private Sub Left_MouseLeave(sender As Object, e As MouseEventArgs)
        atimer.Stop()
        ScrollLeft = True
    End Sub

    Private Sub Right_MouseLeave(sender As Object, e As MouseEventArgs)
        atimer.Stop()
    End Sub

End Class

Если я запускаю это из выражений Blend, проект строится нормально и отображается, но действие прокрутки не работает.

Если я запускаю это из Visual Studio, я получаю сообщение об ошибке со строкой ...

svImages.ScrollToHorizontalOffset(svImages.HorizontalOffset - 0.1)

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

Где я ошибся.

1 Ответ

8 голосов
/ 24 марта 2012

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

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

Обычный способ использовать WinForms - создать специальный делегат и вызвать Control.Invoke, как показано в этой ссылке .

Начиная с WPF, тот же эффект достигается при использовании Диспетчер . Ваш код должен выглядеть так:

this.Dispatcher.Invoke( () => svImages.ScrollToHorizontalOffset(svImages.HorizontalOffset - 0.1));

UPDATE

У меня есть следующий код для работы в VB.NET:

Private Delegate Sub ScrollDelegate(ByVal offset As Double)

Private Sub ScrollLeft(ByVal offset As Double)
    svImages.ScrollToHorizontalOffset(svImages.HorizontalOffset + offset)
End Sub

// ... calling from background thread

Dim slt As ScrollDelegate
slt = New ScrollDelegate(AddressOf ScrollLeft)
Me.Dispatcher.Invoke(slt)

Обновление 2

Код изменен относительно вопроса.

Dim ScrollLeft As Boolean = True
Dim atimer As New System.Timers.Timer()
Dim scrollMethod As ScrollDelegate
Private Delegate Sub ScrollDelegate(ByVal offset As Double)

// ...
    Me.InitializeComponent()
    slt = New ScrollDelegate(AddressOf DoScroll)

// ...

 Private Sub timer_Tick(sender As Object, e As EventArgs)
    If ScrollLeft Then
        Me.Dispatcher.Invoke(slt, -1)
    Else
        Me.Dispatcher.Invoke(slt, 1)
    End If
End Sub

// ...

Private Sub DoScroll(ByVal offset As Double)
    svImages.ScrollToHorizontalOffset(svImages.HorizontalOffset + offset)
End Sub
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...