我正在尝试以编程方式滚动ScrollViewer。但是一旦事件发生,我的UI就会挂起。如果我取出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;
}
答案 0 :(得分:2)
你的循环将无限循环,因为没有任何东西可以使ScrollLeft
或ScrollRight
为假。由于循环没有退出,事件处理程序永远不会完成,并且不会触发新事件。
我建议可以使用故事板动画滚动,然后在动画结束时调查鼠标的状态。
答案 1 :(得分:2)
您的代码似乎期望事件(Left_MouseLeave)将在另一个事件(Left_MouseEnter)仍在执行时触发。
情况并非如此,事件由1个线程提供服务,不会重叠。
您必须更改为更加事件驱动的算法。我没有在WPF中看到MouseHover,所以你需要别的东西。
答案 2 :(得分:2)
您无法从其他线程滚动,但您不必滚动,因为您可以通过一些简单的代码更改来解决问题。
正如其他人所说,当鼠标输入事件工作时你无法获得鼠标离开事件,你必须更改你的代码,以便鼠标输入事件立即返回(顺便说一句,所有事件应该立即返回,否则你程序 - 在极端情况下,整个系统将变得无响应。)
您可以尝试以下两种方法:
向您的班级添加DispatcherTimer,在计时器的Tick事件中滚动固定金额,在鼠标上输入调用计时器Start方法,在鼠标离开调用Stop上。
使用动画,在鼠标输入时使用DoubleAnimation开始滚动,停止动画并在鼠标离开时检查当前值
使用RepeatButton,如果在RepeatButton Click事件上滚动固定数量,则在按下按钮时将重复调用事件(这会稍微改变行为,因为您必须按下按钮而不仅仅是将鼠标悬停在它)。
可能还有很多其他选项,其中没有涉及线程(因为多线程解决方案在这里不起作用)
答案 3 :(得分:0)
这是最终的代码。希望它可以帮助某人:)
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();
}