如何同时更新WPF UI线程?

时间:2015-12-04 23:31:29

标签: c# .net wpf task-parallel-library concurrent-queue

我有scanario,我正在使用TPL以多线程方式从磁盘读取数据。 我有WPF GUI作为进程的主线程,它显示从这些线程读取的数据。

如何在处理时实时更新WPF GUI上的数据? 在这方面我应该如何使用concurrentQueue来允许工作线程和UI线程同时生成和使用数据?

以下是工作线程代码:

   public void ProcessFile(string a_strFilePath)
   {
     try
     {
          var fileType = this.GetFileType(a_strFilePath);
          string assemblyToLoad = string.Format("DirectoryMonitoring.{0}Loader", fileType);
          Assembly assembly = Assembly.LoadFrom(assemblyToLoad + ".dll");

          if (assembly != null)
          {
            Type type = assembly.GetType(assemblyToLoad);
            dynamic instance = Activator.CreateInstance(type);
            FileSchema fileSchema = instance.Read(a_strFilePath);

           //ConcurrentQueue....how can it be used??
          }
   }
   catch (Exception ex)
   {
            //Log.Write(ex.Message);
   }
  }

我的主要WPF GUI只是一个托管其他网格的普通网格。

<Window x:Class="DirectoryMonitoring.UI.View.WndFileContents"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="FileContents" Height="500" Width="700" ResizeMode="NoResize">
<Grid Margin="0,0,0,0">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <!--<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="400" Grid.Row="0">
        <ItemsControl>-->
            <DataGrid  Grid.Row="0" x:Name="grdFilesContents" CanUserReorderColumns="True" CanUserResizeColumns="True" 
                       ItemsSource="{Binding SelectedFileContents}"  IsReadOnly="True" CanUserResizeRows="False" CanUserSortColumns="True" AutoGenerateColumns="False">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Date" Binding="{Binding Path=Date}"  Width="100"/>
                    <DataGridTextColumn Header="Open" Binding="{Binding Path=Open}"  Width="80" />
                    <DataGridTextColumn Header="High" Binding="{Binding Path=High}" Width="80" />
                    <DataGridTextColumn Header="Low" Binding="{Binding Path=Low}" Width="80" />
                    <DataGridTextColumn Header="Close" Binding="{Binding Path=Close}" Width="80" />
                    <DataGridTextColumn Header="Volume" Binding="{Binding Path=Volume}" Width="200" />
                </DataGrid.Columns>
            </DataGrid>
        <!--</ItemsControl>
    </ScrollViewer>-->

    <Grid Grid.Row="1">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" ></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Button VerticalAlignment="Center" HorizontalAlignment="Right" Name="Close" Width="100" Height="20" Grid.Row="0" Grid.Column="0" Margin="5" Click="Close_Click_1">Close</Button>
    </Grid>
</Grid>

那么如何通过使用并发队列来更新上面的简单网格,以便我的工作线程完成其执行,并且UI线程必须同时更新结果。

2 个答案:

答案 0 :(得分:1)

你可以忘记一切,让当前的调度员处理它,例如

Application.Current.Dispatcher.Invoke(() => {
   //Modify Ui here
});

答案 1 :(得分:0)

public void ProcessFile(string a_strFilePath, IProgress<string> reporter)
{
 try
 {
      var fileType = this.GetFileType(a_strFilePath);
      string assemblyToLoad = string.Format("DirectoryMonitoring.{0}Loader", fileType);
      Assembly assembly = Assembly.LoadFrom(assemblyToLoad + ".dll");

      if (assembly != null)
      {
        Type type = assembly.GetType(assemblyToLoad);
        dynamic instance = Activator.CreateInstance(type);
        FileSchema fileSchema = instance.Read(a_strFilePath);

       //ConcurrentQueue....how can it be used??
       reporter.Report("Reporting data back to UI Thread")
      }
}
catch (Exception ex)
{
        //Log.Write(ex.Message);
}
}

然后在你的主UI类

private Progress<string> Reporter = new Progress<string>(OnReport);

void StartProcessFile()
{
     //Wrap is Task/Thread/etc
     new MyClass().ProcessFile(path, Reporter);
}
void OnReport(string data)
{ 
}

有几种方法可以实现,我对ConcurrentQueue在您的代码中扮演的角色有点困惑。 ConcurrentQueue旨在允许多个线程从中读取和写入,而不太关心同步。在那种情况下,如果您使用从ConcurrentQueue中提取的信息来报告回UI线程,则无关紧要,因为OnReport方法一次只能被一个线程调用(UI线程)