我正在开发一个WPF应用程序,其中我有一个带网格的ScrollViewer(16个ColumnDefinitions全部自动宽度),并为每个列分配一个图像。我想要创建的效果是当鼠标进入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
如果我从Expressions Blend运行它,则项目构建正常并显示,但滚动操作无效。
如果我从Visual Studio运行它,我会收到一行错误...
svImages.ScrollToHorizontalOffset(svImages.HorizontalOffset - 0.1)
说InvalidOperationException未被用户代码处理...调用线程无法访问此对象,因为另一个线程拥有它。在窗口加载之前我得到了这个错误。
我哪里出错了。
答案 0 :(得分:8)
错误“调用线程无法访问此对象,因为另一个线程拥有它。”是WinForms和WPF控件的标准。
在WPF和WinForms中,窗口使用一个特定的线程(通常称为UI线程)在屏幕上呈现。有关控件的每个更新/更改操作都应该在该线程上进行以获得成功。
使用WinForms的常用方法是创建一个特殊的委托并调用Control.Invoke,如此link所示。
从WPF开始,使用Dispatcher可以达到同样的效果。您的代码应如下所示:
this.Dispatcher.Invoke( () => svImages.ScrollToHorizontalOffset(svImages.HorizontalOffset - 0.1));
<强>更新强>
我已经在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