简体   繁体   English

在WPF应用程序中正确实现任务

[英]Correctly implementing Tasks in a WPF application

I'm looking for some advice on getting to grips with Task s in WPF and was wondering if anyone could have a look over my code and point out what I'm doing incorrectly? 我正在寻找有关WPF中Task的一些建议,并且想知道是否有人可以看一下我的代码并指出我在做什么错误?

Basically the application takes a postcode from the UI which is used to instantiate a Task service which will get Longitude/Latitude which can be accessed via the instance for use in another service or the UI itself. 基本上,应用程序从UI提取邮政编码,用于实例化Task服务,该服务将获得经度/纬度,可以通过实例访问该经度以用于其他服务或UI本身。

I think I may have a race condition which I'm looking to correct as when ResultTextBlock.Text is set it's a zero, but stepping through instantiation I see those values set. 我认为我可能想解决一个竞态条件,因为将ResultTextBlock.Text设置为零时,但是逐步进行实例化时,我看到那些值已设置。

Any advice on Task implementation and wiring would be greatly appreciated. 任何有关Task实施和接线的建议将不胜感激。

Service Code 服务编号

class PostcodeService
{
    string _result;
    string _postcode;

    HttpResponseMessage _response;        
    RootObject rootObject;

    public double Latitude { get; private set; }
    public double Longitude { get; private set; }        

    public PostcodeService(string postcode)
    {
        this._postcode = postcode;
        rootObject = new RootObject();
    }

    public async Task<string> GetLongLatAsync()
    {        
        using (HttpClient client = new HttpClient())
        {
            client.BaseAddress = new Uri("https://api.postcodes.io/postcodes/" + this._postcode);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/json"));  

            try
            {
                _response = await client.GetAsync(client.BaseAddress);
                if(_response.IsSuccessStatusCode)
                {
                    //cast result into model and then set long/lat properties which can then be used in the UI
                    _result = await _response.Content.ReadAsStringAsync();                     

                    rootObject = JsonConvert.DeserializeObject<RootObject>(_result);
                    Longitude = Double.Parse(rootObject.result.longitude.ToString());
                    Latitude =  Double.Parse(rootObject.result.latitude.ToString());
                }                                      
            }
            catch(Exception ex)
            {
                ex.ToString();
            }
        }

        TaskCompletionSource<string> tc = new TaskCompletionSource<string>(_result);

        return tc.ToString();
    }
}

UI Code UI代码

private void PostcodeButton_Click(object sender, RoutedEventArgs e)
{
    _clearStatus();

    if (_validatePostcode())
    {
        Task T1 = Task.Factory.StartNew(async () =>
        {
            // get long lat from api
            _postcode = new PostcodeService(PostcodeTextBox.Text);
            await _postcode.GetLongLatAsync();
        });

        //Race condition?
        ResultTextBlock.Text = _postcode.Latitude.ToString();
    }
}

Event handlers allow async void to be used 事件处理程序允许使用异步void

Reference Async/Await - Best Practices in Asynchronous Programming 参考Async / Await-异步编程最佳实践

private async void PostcodeButton_Click(object sender, RoutedEventArgs e) {
    _clearStatus();

    if (_validatePostcode()) {
        // get long lat from api
        _postcode = new PostcodeService(PostcodeTextBox.Text);
        await _postcode.GetLongLatAsync(); //Offload UI thread
        //Back on UI thread
        ResultTextBlock.Text = _postcode.Latitude.ToString();
    }
}

Secondly to avoid thread exhaustion, create a single HttpClient instead of creating and disposing it when you need to perform this action 其次,为避免线程耗尽,请在需要执行此操作时创建单个HttpClient而不是创建和处理它

Reference You're using HttpClient wrong 参考您使用的HttpClient错误

The design of the service should be refactored into separate concerns 服务的设计应重构为单独的关注点

public class Location {
    public Location(double lat, double lon) {
        Latitude = lat;
        Longitude = lon;
    }
    public double Latitude { get; private set; }
    public double Longitude { get; private set; }    
}

public class PostcodeService {
    private static Lazy<HttpClient> client;
    static PostcodeService() {
        client = new Lazy<HttpClient>(() => {
            HttpClient httpClient = new HttpClient();
            httpClient.BaseAddress = new Uri("https://api.postcodes.io/postcodes/");
            httpClient.DefaultRequestHeaders.Accept.Clear();
            httpClient.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/json"));
            return httpClient;
        });
    }

    public async Task<Location> GetLongLatAsync(string postcode) {}
        var response = await client.Value.GetAsync(postcode);
        if(response.IsSuccessStatusCode) {
            //cast result into model and then set long/lat properties which can then be used in the UI
            var rootObject = await response.Content.ReadAsAsync<RootObject>();
            var Longitude = Double.Parse(rootObject.result.longitude.ToString());
            var Latitude =  Double.Parse(rootObject.result.latitude.ToString());
            var result = new Location(Latitude, Longitude);
            return result;
        }
        return null;
    }
}

The event handler can now be refactored to 现在可以将事件处理程序重构为

private async void PostcodeButton_Click(object sender, RoutedEventArgs e) {
    _clearStatus();

    if (_validatePostcode()) {
        // get long lat from api
        var service = new PostcodeService();
        var location = await service.GetLongLatAsync(PostcodeTextBox.Text); //Offload UI thread
        //Back on UI thread
        if(location != null) {

            ResultTextBlock.Text = location.Latitude.ToString();
        } else {
            //Some message here
        }

    }
}

Your GetLongLatAsync() method should return a string : 您的GetLongLatAsync()方法应返回一个string

public async Task<string> GetLongLatAsync()
{
    using (HttpClient client = new HttpClient())
    {
        client.BaseAddress = new Uri("https://api.postcodes.io/postcodes/" + this._postcode);
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));

        _response = await client.GetAsync(client.BaseAddress);
        string result = null;
        if (_response.IsSuccessStatusCode)
        {
            //cast result into model and then set long/lat properties which can then be used in the UI
            result = await _response.Content.ReadAsStringAsync();

            rootObject = JsonConvert.DeserializeObject<RootObject>(_result);
            Longitude = Double.Parse(rootObject.result.longitude.ToString());
            Latitude = Double.Parse(rootObject.result.latitude.ToString());
        }
        return result;
    }
}

...and you should simply await GetLongLatAsync() in the UI: ...,您只需在UI中等待GetLongLatAsync()

private async void PostcodeButton_Click(object sender, RoutedEventArgs e)
{
    _clearStatus();
    if (_validatePostcode())
    {
        // get long lat from api
        _postcode = new PostcodeService(PostcodeTextBox.Text);
        string result = await _postcode.GetLongLatAsync();
        ResultTextBlock.Text = result.ToString();
    }
}

You don't need to use a TaskCompletionSource nor start a new Task to call an async method. 您无需使用TaskCompletionSource或启动新的Task来调用异步方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在WPF应用程序中使用任务和回调实现自定义异步WCF调用处理时,UI冻结 - UI Freeze when Implementing custom Asynchronous WCF call handling using tasks and callbacks in WPF application WPF应用中的分派器,实现了多个异步任务 - Dispatcher in WPF apps implementing multiple async Tasks 在WPF应用程序中实现IDataErrorInfo或INotifyDataErrorInfo的限制 - Limitation in Implementing IDataErrorInfo or INotifyDataErrorInfo in WPF application 在WPF应用程序中实现双用户界面 - Implementing dual user interface in WPF application 在我的(WPF MVVM)应用程序中实现条码扫描器 - Implementing barcode scanner in my (WPF MVVM ) application 在 WPF 应用程序中实现 MVVM 模式,方法 - Implementing MVVM pattern in WPF application, methods 如何(正确)更新WPF应用程序的MVVM中的M? - How to (correctly) update the M in MVVM of WPF application? 在WPF应用程序中未正确执行命令绑定 - Command-Binding is not correctly executed in WPF application WPF应用程序DispatcherTimer无法正常运行(滞后) - WPF Application DispatcherTimer not working correctly (lag) 在类库中正确实现缓存以在 asp.net 应用程序中使用 - Implementing cache correctly in a class library for use in an asp.net application
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM