gpt4 book ai didi

c# - WPF 的 Imagecontrol 卡住 UI

转载 作者:太空狗 更新时间:2023-10-29 23:39:20 29 4
gpt4 key购买 nike

我想在我的 WPF 应用程序中显示用户头像。这就是我绑定(bind) Image-Control 的方式:

<Image Source="{Binding Path=Email, Converter={StaticResource GravatarConverter},IsAsync=True}">

其中 GravatarConverter 返回给定电子邮件的 URL。不幸的是,这在加载第一个图像时完全阻塞了我的 UI。请注意,我使用的是“IsAsync=True”。经过一些研究,我发现在应用程序启动时在单独的线程中调用 FindServicePoint 时,我可以解决这个问题:

        Task.Factory.StartNew( () => ServicePointManager.FindServicePoint( "http://www.gravatar.com", WebRequest.DefaultWebProxy ) );

但是当我的应用程序已经在下载图像时 FindServicePoint 尚未完成时,这将不起作用。谁能解释一下为什么 WPF 应用程序根本需要这个 FindServicePoint,为什么它会阻塞 UI 以及如何避免阻塞?

谢谢

更新:事实证明,在 Internet Explorer 的“Internet 选项”->“连接”->“LAN 设置”中取消选中“自动检测设置”后,我的问题就消失了。

我使用这个非常简单的 WPF 应用程序来重现该问题,只需在文本框中插入图像的 URL,然后单击按钮即可。启用“自动检测设置”后,应用程序会在第一次加载图像时卡住几秒钟。使用此选项会立即禁用其加载。

主窗口.xaml

<Window x:Class="WpfGravatarFreezeTest.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>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Grid.Column="0" Grid.Row="0" HorizontalAlignment="Stretch" x:Name="tbEmail" />
<Button Grid.Column="0" Grid.Row="0" Click="buttonLoad_OnClick" HorizontalAlignment="Right">Set Source</Button>
<Image x:Name="img" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" />
</Grid>

主窗口.xaml.cs

using System;
using System.Windows;
using System.Windows.Media.Imaging;

namespace WpfGravatarFreezeTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}

private void buttonLoad_OnClick( object sender, RoutedEventArgs e )
{
try { this.img.Source = new BitmapImage(new Uri(this.tbEmail.Text)); }
catch( Exception ){}
}
}
}

最佳答案

因为 IsAsync=True 仅以异步方式运行绑定(bind)进程,所以会发生阻塞 UI。在您的情况下,您在转换过程中有一个长时间运行的操作。要解决这个问题,您应该创建像这样异步显示结果的转换器(基于 this answer ):

创建任务完成通知器:

public sealed class TaskCompletionNotifier<TResult> : INotifyPropertyChanged
{
public TaskCompletionNotifier(Task<TResult> task)
{
Task = task;
if (task.IsCompleted) return;
task.ContinueWith(t =>
{
var temp = PropertyChanged;
if (temp != null)
{
temp(this, new PropertyChangedEventArgs("Result"));
}
});
}

// Gets the task being watched. This property never changes and is never <c>null</c>.
public Task<TResult> Task { get; private set; }

// Gets the result of the task. Returns the default value of TResult if the task has not completed successfully.
public TResult Result { get { return (Task.Status == TaskStatus.RanToCompletion) ? Task.Result : default(TResult); } }

public event PropertyChangedEventHandler PropertyChanged;

}

创建实现 MarkupExtention 的异步转换器:

public class ImageConverter: MarkupExtension, IValueConverter
{

public ImageConverter()
{
}

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return new BitmapImage();
var task = Task.Run(() =>
{
Thread.Sleep(5000); // Perform your long running operation and request here
return value.ToString();
});

return new TaskCompletionNotifier<string>(task);
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}

public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}

}

在 Xaml 中使用它:

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>

<TextBox x:Name="uri" Grid.Row="0" Text="{Binding ImageUri, ElementName=main}"/>
<Image Grid.Row="1" DataContext="{Binding Text, ElementName=uri, Converter={local:ImageConverter}}" Source="{Binding Path=Result, IsAsync=True}"/>

</Grid>

更新 2似乎 Image 控制自己异步加载图像。你是对的,第一次加载需要很多时间。您可以使用这样的代码:

    try
{
var uri = Uri.Text;
var client = new WebClient();
var stream = await client.OpenReadTaskAsync(uri);
var source = new BitmapImage();
source.BeginInit();
source.StreamSource = stream;
source.EndInit();
Img.Source = source;


}
catch (Exception) { }

但它的性能并不比您的变体好。

关于c# - WPF 的 Imagecontrol 卡住 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19376239/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com