2013-10-15 16 views
5

Tôi muốn hiển thị một người dùng Gravatar trong ứng dụng WPF của tôi. Đây là cách tôi ràng buộc Điều khiển Hình ảnh:Imagecontrol của WPF đóng băng giao diện người dùng

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

Trường hợp GravatarConverter trả về URL cho Email đã cho. Rất tiếc, điều này đang chặn hoàn toàn giao diện người dùng của tôi khi tải Hình ảnh đầu tiên. Xin lưu ý rằng tôi đang sử dụng "IsAsync = True". Sau khi một số nghiên cứu tôi phát hiện ra rằng tôi có thể hack xung quanh vấn đề này khi gọi FindServicePoint trong một thread riêng biệt trên các ứng dụng khởi động:

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

Nhưng đây không phải là làm việc khi FindServicePoint là không hoàn thành trong khi ứng dụng của tôi đã được tải một hình ảnh. Có thể ai đó vui lòng giải thích lý do tại sao một WPF-App cần FindServicePoint này ở tất cả, tại sao điều này là ngăn chặn giao diện người dùng và làm thế nào để tránh chặn?

Cảm ơn

Cập nhật: Khi nó quay ra vấn đề của tôi đã biến mất sau khi tôi bỏ chọn "Automatic detect settings" trong Internet Explorers "Internet Options" -> "Connections" -> "LAN Settings".

Tôi đã sử dụng ứng dụng WPF rất đơn giản này để tái tạo sự cố chỉ bằng cách chèn url cho hình ảnh trong hộp văn bản và nhấp vào nút. Với "Cài đặt tự động phát hiện", ứng dụng sẽ đóng băng trong một vài giây khi lần đầu tiên một hình ảnh được tải. Với tùy chọn này đã tắt tải ngay lập tức.

MainWindow.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>   

MainWindow.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){}    
     } 
    } 
} 

Trả lời

2

Chặn happans UI vì IsAsync = True chạy theo cách async chỉ quá trình ràng buộc. Trong trường hợp của bạn, bạn có một hoạt động chạy dài trong quá trình chuyển đổi. Để giải quyết điều này, bạn nên tạo chuyển đổi mà trình bày các kết quả không đồng bộ như thế này (dựa trên this answer):

Tạo công việc complition notifier:

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; 

} 

Tạo chuyển đổi async thực hiện 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; 
    } 

} 

Sử dụng trong 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> 

Cập nhật 2 Có vẻ như ảnh hình ảnh kiểm soát tải không đồng bộ của chính nó. Bạn đang tải đầu tiên phải mất rất nhiều thời gian. Bạn có thể sử dụng mã như sau:

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) { } 

Nhưng hiệu suất của nó không tốt hơn biến thể của bạn.

+0

Cảm ơn bạn rất nhiều.Thật không may điều này vẫn đóng băng giao diện người dùng của tôi. Có vẻ như nó không quan trọng nếu tôi thực hiện điều này một cách không đồng bộ - vấn đề có vẻ là cuộc gọi ServicePointManager.FindServicePoint này được thực hiện một lần cho mỗi ứng dụng lần đầu tiên một hình ảnh từ xa được tải xuống. – user1130329

+0

Trong trường hợp của tôi tất cả các công trình mà không đóng băng. Bạn gọi ServicePointManager.FindServicePoint ở đâu? Bạn có thể cung cấp một số mã không? Ngoài ra phải trả attantion rằng tôi đặt IsAsync = True. – Deffiss

+1

OK Tôi đã tìm thấy "lỗi" - nhưng điều này thực sự lạ: nó phải làm với các thiết lập internet trong Internet Explorer. Tôi đã "Tự động phát hiện cài đặt" trong "Cài đặt" -> "Kết nối" -> "Cài đặt Lan" được kích hoạt. Khi tôi tắt tất cả mọi thứ tải hoàn hảo, khi tôi kích hoạt nó nó bị đóng băng. Vì vậy, điều này có vẻ là một vấn đề hệ điều hành? – user1130329

Các vấn đề liên quan