2014-07-14 2 views
0

많은 이미지를 바인딩하는 WPF 목록 상자가 있습니다. 각 이미지는 로컬 디스크에서 가져 오거나 Exe에서 아이콘을 가져올 수 있습니다.WPF 값 변환기에서 비동기 로딩 이미지

모든 구문 분석 코드를 MultiValueConverter에 넣었습니다. 하지만 이제는 UI를 차단하는 것처럼 보입니다. 그 비동기를 만드는 방법?

코드 샘플 : 당신은 MSDN에서 Binding

IsAsync 속성을 활용할 수 https://github.com/qianlifeng/Wox/blob/master/Wox/Converters/ImagePathConverter.cs#L53

+2

여기에 코드의 관련 부분을 게시해야합니다. – Clemens

답변

5

:

사용 IsAsync 속성을 당신의 바인딩 소스의 get 접근이 속성이 오래 걸릴 수 있습니다 때 시각. 한 예로 웹에서 다운로드하는 접근자인 의 이미지 속성이 있습니다. IsAsync를 true로 설정하면 다운로드하는 동안 UI가 차단되지 않습니다.

예를

<Image Source="{Binding MyImage,IsAsync=True, Converter={StaticResource MyConverter}}" /> 

Binding.IsAsync


비동기 변환기

에 나는 비동기 변환기를 만들 수 관리

namespace CSharpWPF 
{ 
    class AsyncConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      return new AsyncTask(() => 
      { 
       Thread.Sleep(4000); //long running job eg. download image. 
       return "success"; 
      }); 
     } 

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

     public class AsyncTask : INotifyPropertyChanged 
     { 
      public AsyncTask(Func<object> valueFunc) 
      { 
       AsyncValue = "loading async value"; //temp value for demo 
       LoadValue(valueFunc); 
      } 

      private async Task LoadValue(Func<object> valueFunc) 
      { 
       AsyncValue = await Task<object>.Run(()=> 
        { 
         return valueFunc(); 
        }); 
       if (PropertyChanged != null) 
        PropertyChanged(this, new PropertyChangedEventArgs("AsyncValue")); 
      } 

      public event PropertyChangedEventHandler PropertyChanged; 

      public object AsyncValue { get; set; } 
     } 
    } 
} 

이 변환기는 비동기 적으로 작업을 실행합니다

클래스 AsyncTask 내에서 장기 실행 작업을 캡슐화하고 그것은 또한 따라서를 업데이트 알림을 사용 INotifyPropertyChanged를 구현으로 AsyncValue에 결과를 설정합니다 AsyncTask의 인스턴스를 반환합니다 UI

사용

<Grid xmlns:l="clr-namespace:CSharpWPF"> 
    <Grid.Resources> 
     <l:AsyncConverter x:Key="AsyncConverter" /> 
    </Grid.Resources> 
    <TextBlock DataContext="{Binding MyProperty,Converter={StaticResource AsyncConverter}}" 
       Text="{Binding AsyncValue}" /> 
</Grid> 

아이디어는 변환기와 t로 소자의 DataContext 결합하는 그 예를 상기

exmaple 너무 IMultiValueConverter 사용될 수있는 IValueConverter 동일한 접근되어 쉽게 데모 텍스트 블록의 텍스트 속성을 사용하는 새로운 데이터 콘텍스트의 AsyncValue에 속성을 요구.

+1

이것은 MyImage getter를 변환기 (OP가 요구 한 것)가 아닌 비동기식으로 만 호출합니다. 다른 리소스 (예 : MSDN * : 'IsAsync 속성 사용')에서 인용을 표시하십시오. – Clemens

+0

나는 그 점을 얻었다. 이 문제를 해결하기 위해 calculate 속성을 사용하여 변환기 대신 장시간 실행되는 함수를 실행할 수 있습니다. 변환기를 비동기로 사용하는 방법을 찾으려고합니다. – pushpraj

+1

가능한 해결 방법은 변환기없이 비동기 적으로 바인딩 할 수있는 또 다른 뷰 모델 속성입니다. – Clemens

0

먼저 응답자를 위해 쉽게 재현 할 수 있도록 몇 가지 샘플 코드를 제공해야합니다.

  1. 내가 IsAsync 동적 이미지를로드 할 때이 시간에 메모리 누수로 이어질 것을 관찰 :

    IsAsync

    때문에 아래의 이유로 도움이되지 않습니다 바인딩 IsAsync를 사용

    도움이되지 않습니다.그래서 설탕 사탕을 피하기 IsAsync 재산

  2. IsAsync 항상을 위해 중단 영업 이익은 웹에서 이미지를로드하려고하지만 그래서 다시 응용 프로그램을 메인 스레드에서 DNS 해결되는 WPF question here에서 언급 한 문제의 사례로 도움이되지 않습니다
동안

솔루션을 사용하면 WPF에서

세부 사항을 바인딩 속성을 첨부한다 :

  1. 당신은 솜을 넣어한다 XAML에서 Source에 전자 썸네일 이미지
  2. 쓰기 한 배경 및 업데이트 이미지 소스에서 이미지를로드 할 연결된 속성 클래스 때
<Image my:ImageAsyncHelper.SourceUri="{Binding Author.IconUrl}" /> 
사용 가능한 (사용 사례 유사한 종류의 아래 샘플 코드)

연결된 속성 클래스

public class ImageAsyncHelper : DependencyObject 
{ 
    public static Uri GetSourceUri(DependencyObject obj) { return (Uri)obj.GetValue(SourceUriProperty); } 
    public static void SetSourceUri(DependencyObject obj, Uri value) { obj.SetValue(SourceUriProperty, value); } 
    public static readonly DependencyProperty SourceUriProperty = DependencyProperty.RegisterAttached("SourceUri", typeof(Uri), typeof(ImageAsyncHelper), new PropertyMetadata 
    { 
    PropertyChangedCallback = (obj, e) => 
    { 
     ((Image)obj).SetBinding(Image.SourceProperty, 
     new Binding("VerifiedUri") 
     { 
      Source = new ImageAsyncHelper { GivenUri = (Uri)e.NewValue }, 
      IsAsync = true, 
     }); 
    } 
    }); 

    Uri GivenUri; 
    public Uri VerifiedUri 
    { 
    get 
    { 
     try 
     { 
     Dns.GetHostEntry(GivenUri.DnsSafeHost); 
     return GivenUri; 
     } 
     catch(Exception) 
     { 
     return null; 
     } 

    } 
    } 
} 

당신이 위에 정의 된 특성과 IMultiValueConverter를 사용해야하는 경우 다음은 XAML 코드를 아래와 같이 가야한다 :

첨부 재산권 IMultiValueConverter

<Image> 
    <my:ImageAsyncHelper.SourceUri> 
     <MultiBinding Converter="{StaticResource MyImageMultiValueConverter}"> 
      <Binding Source="Author" Path="IconUrl"/> <!-- Binding Parameters --> 
      <Binding Path="ImageType"/> <!-- Binding Parameters --> 
      <Binding Path="MyParameterToConverter"/> <!-- Binding Parameters --> 
     </MultiBinding> 
    </my:ImageAsyncHelper.SourceUri> 
</Image> 

참조

  1. 링크 How can I keep a WPF Image from blocking if the ImageSource references an unreachable Url?
  2. Using multibinding to set custom attached property in WPF
+1

이 솔루션은 사용하지 말라고 경고 함에도 불구하고 ('new Binding()'코드에서)'IsAsync'에 전적으로 의존하는 것 같습니다. –