在繁忙的UI线程中拖动WPF滑块会导致意外值

在繁忙的UI线程中拖动WPF滑块会导致意外值,wpf,multithreading,slider,Wpf,Multithreading,Slider,编辑:Slider.ValueChanged事件中有一个长时间锁定。消除这一点可以停止这种奇怪。不好的做法,但这种行为对我来说仍然没有意义。这可能与消息队列有关,但如果可能的话,我希望得到一个解释 当UI线程*上有重要工作时,WPF滑块不会像预期的那样与鼠标交互。如果我向一个方向拖动拇指,拇指通常会在鼠标光标前面前进,然后返回。移动只会导致值更改事件增加,但事件有时会减少。有时这种振荡也发生在鼠标光标后面。似乎鼠标的位置是由其当前速度预测的 我能改变这种行为吗,还是我做错了什么 切换IsSnap

编辑:Slider.ValueChanged事件中有一个长时间锁定。消除这一点可以停止这种奇怪。不好的做法,但这种行为对我来说仍然没有意义。这可能与消息队列有关,但如果可能的话,我希望得到一个解释

当UI线程*上有重要工作时,WPF滑块不会像预期的那样与鼠标交互。如果我向一个方向拖动拇指,拇指通常会在鼠标光标前面前进,然后返回。移动只会导致值更改事件增加,但事件有时会减少。有时这种振荡也发生在鼠标光标后面。似乎鼠标的位置是由其当前速度预测的

我能改变这种行为吗,还是我做错了什么

切换IsSnaptoticEnabled没有帮助

*将大位图源指定给图像。BitmapSource是在工作线程中创建的

<Window x:Class="WPFSliderBug.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Image Name="image1" Stretch="Fill" />
    <Slider HorizontalAlignment="Right" Name="slider1" VerticalAlignment="Stretch" Orientation="Vertical" />
</Grid>
</Window>

xaml.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;

using System.Threading;

namespace WPFSliderBug
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private volatile bool m_run = true;
        private double m_sliderValue;

        public MainWindow()
        {
            InitializeComponent();

            this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);
            this.slider1.Minimum = 1;
            this.slider1.Maximum = 30;
            this.slider1.SmallChange = 0.5;
            this.slider1.LargeChange = 0.5;
            this.slider1.TickFrequency = 0.5;
            this.slider1.TickPlacement = System.Windows.Controls.Primitives.TickPlacement.Both;
            this.slider1.ValueChanged += new RoutedPropertyChangedEventHandler<double>(slider1_ValueChanged);

            Thread t = new Thread((unused_state) =>
            {
                while (m_run)
                {

                    BitmapSource bmp;
                    lock (this)
                    {
                        bmp = ToBitmapSource();
                        bmp.Freeze();
                    }

                    this.Dispatcher.Invoke(new Action(delegate()
                    {
                        image1.Source = bmp;
                    }));
                }
            });

            t.Start();
        }

        void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            lock (this)
            {
                m_sliderValue = e.NewValue;
            }
        }

        void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {

                m_run = false;
        }

        public BitmapSource ToBitmapSource()
        {
            Random rng = new Random();
            double dpi = 96;
            int bytesPerPixel = 1;
            int width = 2048;
            int height = 2048;

            int stride = ((width * 32 + 31) & ~31) / 8;

            UInt32[] pixelData = new UInt32[width * height];
            for (int i = 0; i < pixelData.Length; ++i)
            {
                double r = rng.NextDouble();
                r = Math.Sin(r) * Math.Cos(r) + Math.Asin(r);
                pixelData[i] = (uint)(r * UInt32.MaxValue);
            }


            BitmapSource bmpSource = BitmapSource.Create(width, height, dpi, dpi,
                PixelFormats.Bgr32, null, pixelData, stride);

            return bmpSource;
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Data;
使用System.Windows.Media;
使用System.Windows.Media.Imaging;
使用系统线程;
名称空间WPFSliderBug
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
private volatile bool m_run=true;
私有双m_sliderValue;
公共主窗口()
{
初始化组件();
this.Closing+=新的System.ComponentModel.CancelEventHandler(MainWindow\u Closing);
this.slider1.Minimum=1;
this.slider1.Maximum=30;
this.slider1.SmallChange=0.5;
this.slider1.LargeChange=0.5;
this.slider1.TickFrequency=0.5;
this.slider1.TickPlacement=System.Windows.Controls.Primitives.TickPlacement.Both;
this.slider1.ValueChanged+=新路由属性changedEventHandler(slider1\u ValueChanged);
线程t=新线程((未使用的_状态)=>
{
while(m_run)
{
位图源bmp;
锁(这个)
{
bmp=ToBitmapSource();
bmp.Freeze();
}
this.Dispatcher.Invoke(新操作(委托)()
{
image1.Source=bmp;
}));
}
});
t、 Start();
}
无效滑块1_值已更改(对象发送方,RoutedPropertyChangedEventArgs e)
{
锁(这个)
{
m_sliderValue=e.NewValue;
}
}
无效主窗口\u关闭(对象发送方,System.ComponentModel.CancelEventArgs e)
{
m_run=false;
}
公共BitmapSource ToBitmapSource()
{
随机rng=新随机();
双dpi=96;
int字节/像素=1;
整数宽度=2048;
内部高度=2048;
步幅=((宽度*32+31)和~31)/8;
UInt32[]像素数据=新UInt32[宽度*高度];
对于(int i=0;i
您是否有
记号
,带有
IsSnapToTickEnabled=true
?无论是真是假,行为都是一样的。我无法重现这种行为,我承认我没有对WPF视觉效果做任何事情,只是用睡眠任务来支撑UI线程。这是我们可以看到的小型C#,XAML应用程序中可以复制的东西吗?示例项目?我想看看这部电影的效果。无论如何,我的建议是在Slider.Value属性上使用数据绑定,并将绑定延迟设置为~50ms。拖动滑块时,使用ValueChanged可能会执行大量代码。在那之后,BackgroundWorker可能没有什么影响。@Corrove,我的示例代码是否显示出不稳定的滑块拇指?