我有一个通过一些滑块修改的图像,其值被发送到一个程序(重新)生成一个BitmapSource的方法。
目前事情很麻烦,因为滑块“运动滞后。我认为这是由于Update
方法的阻塞性质。
我试图让事情更加异步"但显然没有成功,因为滑块移动仍然是滞后的。
我在下面发布我的代码,问题是:我做错了什么,以及在WPF中异步更新程序生成的图像的正确方法是什么?
需要注意的一点是,IDE抱怨没有等待Update()
次呼叫,并且#34;在呼叫完成之前继续执行",但我不确定这意味着什么,或者我该怎么办呢。
MainWindow.xaml
<Window x:Class="Miotec.FranjasSenoidais.MainWindow"
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:local="clr-namespace:Miotec.FranjasSenoidais"
xmlns:toolkit="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d"
Title="MainWindow">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid x:Name="Imagem" Grid.Row="0" Grid.Column="0">
<Image x:Name="franjas" Width="800" Height="600"
Source="{Binding ImageSource}"/>
</Grid>
<Grid x:Name="SliderLateral" Grid.Row="0" Grid.Column="1">
<toolkit:RangeSlider Orientation="Vertical"
Maximum="1" Minimum="0" Step="0.01"
HigherValue="{Binding Maximo}"
LowerValue="{Binding Minimo}"/>
</Grid>
<Grid x:Name="SliderEspessuraFranja" Grid.Row="1" Grid.Column="0">
<Slider Orientation="Horizontal" Value="{Binding Espessura}"
Minimum="4" Maximum="16"/>
</Grid>
</Grid>
</Window>
MainWindow.xaml.cs(为简洁起见,代码中的DataContext)
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
namespace Miotec.FranjasSenoidais
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public double Maximo
{
get { return _maximo; }
set
{
_maximo = value;
RaisePropertyChanged("Maximo");
Update();
}
}
double _maximo = 1;
public double Minimo
{
get { return _minimo; }
set
{
_minimo = value;
RaisePropertyChanged("Minimo");
Update();
}
}
double _minimo = 0;
public int Espessura
{
get { return _espessura; }
set
{
_espessura = value;
RaisePropertyChanged("Espessura");
Update();
}
}
int _espessura = 10;
public BitmapSource ImageSource { get { return _imageSource; } }
BitmapSource _imageSource;
private async Task Update()
{
await Dispatcher.BeginInvoke(new Action(() =>
{
// somewhat lengthy operation
_imageSource = FranjasSenoidais.Criar((int)franjas.Width,
(int)franjas.Height,
Maximo, Minimo,
Espessura);
}));
RaisePropertyChanged("ImageSource");
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
}
FranjasSenoidais.cs
public static class FranjasSenoidais
{
public static BitmapSource Criar(int largura,
int altura,
double maximo,
double minimo,
int espessura)
{
if (largura < 2 || altura < 2)
return null;
var targetBitmap = new RenderTargetBitmap(largura, altura,
96, 96,
PixelFormats.Pbgra32);
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
double xcenter = largura * 0.5;
double ycenter = altura * 0.5;
dc.DrawEllipse(Brushes.Black, null, new Point(xcenter, ycenter), espessura, espessura);
}
targetBitmap.Render(visual);
targetBitmap.Freeze();
return targetBitmap;
}
}
答案 0 :(得分:1)
我认为你只需要做一些改变。 @酷蓝评论是对的。只需将调度移动到INotify实现中,然后在任务上排队cpu绑定进程。请确保从该线程更改属性,请参阅以下内容:
private void Update() {
Task.Run(new Action(() => {
// somewhat lengthy operation
_imageSource = FranjasSenoidais.Criar((int)franjas.Width,
(int)franjas.Height,
Maximo, Minimo,
Espessura);
RaisePropertyChanged("ImageSource");
}));
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string name) {
Application.Current.Dispatcher.Invoke(() => {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}, System.Windows.Threading.DispatcherPriority.Background);
}