簡體   English   中英

綁定任務 <T> 屬性並將IsAsync設置為true

[英]Binding to Task<T> property and seting IsAsync to true

我試圖找出一種將視圖綁定到需要使用async方法填充的viewmodel屬性的好方法。 我最新得到的就是像這樣使用IsAsync

ViewModel.cs

public class ViewModel
{
    public Task<string> Name { get; set; }

    public ViewModel()
    {
        Name = GetNameAsync();
    }

    public async Task<string> GetNameAsync()
    {
        return await Task.Run(async () =>
        {
            await Task.Delay(5000);
            return "Foo";
        });
    }
}

View.xaml

<Label Content="{Binding Name.Result, IsAsync=true}" />

它似乎可以工作,但是我不確定是否正在使用IsAsync ,因為應該使用它。 文檔沒有說明與Task相關的任何內容,並且在stackoverflow上也有此注釋 ,指出IsAsync與C# async不相關。

這樣的實現會出什么問題?

處理這種“一次性”異步屬性的最干凈方法是使用Stephen Cleary的Nito.Asyncex庫(在Nuget中提供)中的NotifyTaskCompletetion。

您的ViewModel會變成

public class ViewModel
{
    public INotifyTaskCompletion<string> Name { get; set; }

    public ViewModel()
    {
        Name = NotifyTaskCompletetion.Complete(GetNameAsync());
    }

    private async Task<string> GetNameAsync()
    {
        return await Task.Run(async () =>
        {
            await Task.Delay(5000);
            return "Foo";
        });
    }
}

然后,您將綁定到Name.Result作為標准綁定,不需要IsAsync。

更多細節在這里

更正IsAsync選項與Task無關,它只是告訴UI顯示回退值,而不會在get調用運行時阻塞。

您的代碼可能會出問題。 嗯,我想如果有任何實際錯誤,我必須進行測試以解決問題。 您有很多“壞”的事情。

  1. 構造函數中的代碼。 您可以保留任務引用,因此,它並非一無是處,但通常,您不應在構造函數中使用像這樣的代碼

  2. 在任務上調用.Result。 這可能導致死鎖

  3. 具有異步任務,但不等待它。

  4. 使用Task.Run在任務內部? 您可以直接調用await Task.Delay

我將如下重構您的代碼

視圖模型

public class ViewModel : INotifyPropertyChanged
{
    private string name
    public string Name {
        get {return name;}
        set {
               name = value;
               PropertyChanged("Name");
        }
    public ICommand GetNameAsync;

    private void PropertyChanged(string prop)
    {
       if( PropertyChanged != null )
       {
          PropertyChanged(this, new PropertyChangedEventArgs(prop);
       }
    }


    public ViewModel()
    {
         Name="Loading...";
         GetNameAsync =  new AsyncCommand(async () => {Name = await GetNameAsync()});
    }

    private async Task<string> GetNameAsync()
    {
        await nameService.getName();
    }
}

XAML

<Window xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandAction Command="{Binding GetNameAsync}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>

    <Label Content="{Binding Name}" />
</Window>

現在,您的Xaml將在窗口加載時調用GetName函數,標簽將顯示“ Loading ...”,直到GetName函數完成,然后將其更新為Name。

Unfortuately

  1. WPF沒有AsyncCommand。

    您必須自己制作,或使用第三方框架中的一個(請參見下文)

  2. INotifyPropertyChanged令人討厭輸入。

    我建議使用Fody及其INotifyPropertyChanged插件https://github.com/Fody

AsyncCommand

https://mike-ward.net/2013/08/09/asynccommand-implementation-in-wpf/

using System;  
using System.Threading.Tasks;  
using System.Windows.Input;  

namespace OpenWeather.Command  
{  
    internal class AsyncCommand : ICommand  
    {  
        private readonly Func<Task> _execute;  
        private readonly Func<bool> _canExecute;  
        private bool _isExecuting;  

        public AsyncCommand(Func<Task> execute) : this(execute, () => true)  
        {  
        }  

        public AsyncCommand(Func<Task> execute, Func<bool> canExecute)  
        {  
            _execute = execute;  
            _canExecute = canExecute;  
        }  

        public bool CanExecute(object parameter)  
        {  
            return !(_isExecuting && _canExecute());  
        }  

        public event EventHandler CanExecuteChanged;  

        public async void Execute(object parameter)  
        {  
            _isExecuting = true;  
            OnCanExecuteChanged();  
            try  
            {  
                await _execute();  
            }  
            finally  
            {  
                _isExecuting = false;  
                OnCanExecuteChanged();  
            }  
        }  

        protected virtual void OnCanExecuteChanged()  
        {  
            if (CanExecuteChanged != null) CanExecuteChanged(this, new EventArgs());  
        }  
    }  
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM