Livetを使って非同期でCollection表示

#初めに
Livetを覚え、自分で作ったコンソールプログラムを簡単に操作させたかったので、ボタンを押すとipconfig.exeを実行して、その結果をListBoxに表示するサンプルプログラムを書いた。
asyncとawaitを使うと比較的簡単に書くことができた。
#サンプルプログラム
```csharp:MainWindowViewModel.cs
using System;
using System.Collections.ObjectModel;

using Livet;

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

namespace SampleAsync.ViewModels
{
    public class MainWindowViewModel : ViewModel
    {

        #region Console変更通知プロパティ
        private ObservableCollection<string> _Console = 
            new ObservableCollection<string>();

        public ObservableCollection<string> Console
        {
            get
            { return _Console; }
            set
            { 
                if (_Console == value)
                    return;
                _Console = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        public void Initialize()
        {
        }

        public async void Execute()
        {
            var cmd = @"C:\Windows\System32\ipconfig.exe";
            var p = new Process();
            var pi = p.StartInfo;
            pi.FileName = cmd;
            pi.CreateNoWindow = true;
            pi.UseShellExecute = false;
            pi.RedirectStandardOutput = true;

            p.Start();
            Func<Task> act = async () =>
            {
                while (!p.StandardOutput.EndOfStream)
                {
                    var line = await p.StandardOutput.ReadLineAsync();
                    Console.Add(line.Replace("\r\n", "\n"));
                    await Task.Delay(1000);
                }
            };
            await act();
        }
    }
}

```
```xml:MainWindow.xaml
<Window x:Class="SampleAsync.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:v="clr-namespace:SampleAsync.Views"
        xmlns:vm="clr-namespace:SampleAsync.ViewModels"
        Title="MainWindow" Height="350" Width="525">
    
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>
    
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="ContentRendered">
            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Initialize"/>
        </i:EventTrigger>

        <i:EventTrigger EventName="Closed">
            <l:DataContextDisposeAction/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="43*"/>
            <RowDefinition Height="276*"/>
        </Grid.RowDefinitions>
        <Button Content="実行" HorizontalAlignment="Left" Margin="23,10,0,0" VerticalAlignment="Top" Width="75">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <l:LivetCallMethodAction MethodName="Execute" MethodTarget="{Binding Mode=OneWay}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
        <ListBox ItemsSource="{Binding Console}" Grid.Row="1"/>
    </Grid>
</Window>

```

##実際のプログラムでの問題
上記コードを実行すると、一見うまく動いているように見えるが、大量のデータをインポートするときメッセージが逐次表示されず、最後に一括で表示されてしまう。
上記サンプルのようにawait Task.Delay(1)とかいれるとメッセージは表示されるが、Windowsは固まったままになる。
調べたところ、p.StandardOutput.EndOfStream でしばらく待ちになり画面が固まっていることが分かった。
Executeの部分を下記のように変更することにより問題が解消した。

```csharp
        public async void Execute()
        {
            var cmd = @"C:\Windows\System32\ipconfig.exe";
            var p = new Process();
            var pi = p.StartInfo;
            pi.FileName = cmd;
            pi.CreateNoWindow = true;
            pi.UseShellExecute = false;
            pi.RedirectStandardOutput = true;

            p.Start();
            Func<System.IO.StreamReader, Task<bool>> EndOfStreamAsync = async (sr) =>
            {
                bool sts = false;
                await Task.Run(() => { sts = sr.EndOfStream; });
                return sts;
            };
            Func<Task> act = async () =>
            {
                while (await EndOfStreamAsync(p.StandardOutput) == false)
                {
                    var line = await p.StandardOutput.ReadLineAsync();
                    Console.Add(line.Replace("\r\n", "\n"));
                    await Task.Delay(1000);
                }

            };
            await act();
            
        }

```

EndOfStreamの部分を別スレッドにして解決した。