2012年11月20日火曜日

非同期でWebページを取得する

HttpClientを使って、指定したURLのWebページを取得」の場合、Webページの取得に時間がかかると、アプリケーションが"応答なし"になってしまいます。
Task.Factory.StartNew で 非同期処理」の方法で、Webページの取得中でもキャンセルなどができるようにしています。
ステータスバーに取得時間を表示します。



MainWindow.xaml


<Window x:Class="WpfApplication6.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="250" Width="425">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <DockPanel Grid.Row="0" LastChildFill="True">
            <Button DockPanel.Dock="Right" Click="cancelButton_Click">×</Button>
            <Button DockPanel.Dock="Right" Click="Button_Click">Get</Button>
            <TextBox DockPanel.Dock="Right" Name="urlTextBox" />
        </DockPanel>
        <TextBox Grid.Row="1" Name="contentTextBox"
                 ScrollViewer.HorizontalScrollBarVisibility="Auto"
                 ScrollViewer.VerticalScrollBarVisibility="Auto" />
        <StatusBar Grid.Row="2">
            <TextBlock Name="logTextBlock"
                       Text="{Binding Path=StatusAndElapsedTime,Mode=OneWay,NotifyOnTargetUpdated=True}"
                       TargetUpdated="logTextBox_TargetUpdated" />
        </StatusBar>
    </Grid>
</Window>

MainWindow.xaml.cs



using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;

namespace WpfApplication6
{
    public partial class MainWindow : Window
    {
        private HttpClient client = new HttpClient();
        private Message message = new Message();
        private Task<string> task;

        public MainWindow()
        {
            InitializeComponent();
         
            this.logTextBlock.DataContext = this.message;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            string url = this.urlTextBox.Text;
            this.client.CancelPendingRequests();
            task = Task.Factory.StartNew(() => GetWebContent(url));
        }

        private string GetWebContent(string url)
        {
            this.message.Status = TaskStatus.Running;

            Task<string> innerTask = this.client.GetStringAsync(url);
            string content = innerTask.Result;

            this.message.Status = TaskStatus.RanToCompletion;
            return content;
        }

        private void logTextBox_TargetUpdated(object sender, DataTransferEventArgs e)
        {
            if (this.message.Status == TaskStatus.RanToCompletion)
            {
                this.contentTextBox.Text = task.Result;
            }
        }

        private void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            this.client.CancelPendingRequests();
            this.message.Status = TaskStatus.Canceled;
        }
    }
}

Message.cs

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading.Tasks;

namespace WpfApplication6
{
    public class Message : INotifyPropertyChanged
    {
        public Stopwatch Stopwatch { get; set; }

        private TaskStatus status = TaskStatus.Created;
        public TaskStatus Status
        {
            get { return status; }
            set
            {
                if (value != this.status)
                {
                    if (value == TaskStatus.RanToCompletion)
                    {
                        this.Stopwatch.Stop();
                    }
                    else if (value == TaskStatus.Running)
                    {
                        this.Stopwatch.Restart();
                    }
                    this.status = value;
                    NotifyPropertyChanged("Status");
                    NotifyPropertyChanged("StatusAndElapsedTime");
                }
            }
        }

        public string StatusAndElapsedTime
        {
            get
            {
                return this.status + " " +
                    ((this.status == TaskStatus.RanToCompletion) ? this.Stopwatch.Elapsed.ToString() : "");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        public Message()
        {
            this.Stopwatch = new Stopwatch();
        }
    }
}

0 件のコメント:

コメントを投稿