2016-09-14 9 views
0

Я хочу получить изображение каждые 3 секунды с ip-камеры и поместить его в элемент управления изображением (приложение WPF).Захват изображения с помощью WebRequest вызывает зависание пользовательского интерфейса

Я использую этот код:

DispatcherTimer определение

DispatcherTimer dispatcherTimer = new DispatcherTimer(TimeSpan.FromSeconds(3), DispatcherPriority.Background, DispatcherTimer_Tick, Application.Current.Dispatcher); 

Изображение захватывая код

private void DispatcherTimer_Tick(object sender, EventArgs evA) 
    { 
     Dispatcher.Invoke(DispatcherPriority.Background, 
     new Action(() => 
     { 
      try 
      { 
       BitmapFrame src; 
       var webRequest = (HttpWebRequest)WebRequest.Create(@"http://camera_ip/cgi-bin/video.cgi?msubmenu=jpg"); 
       webRequest.Credentials = new NetworkCredential("user", "password"); 
       webRequest.Proxy = null; 

       var response = (HttpWebResponse)webRequest.GetResponse(); 
       var stream = response.GetResponseStream(); 
       var streamReader = new StreamReader(stream); 
       src = BitmapFrame.Create(streamReader.BaseStream); 

       imageTelecamera.BeginInit(); 
       imageTelecamera.Source = src; 
       imageTelecamera.EndInit(); 

       } 
      catch (Exception ex) 
      { 
       DoLogD($"Error: {ex.Message}"); 
      } 
     } 
     )); 
    } 

Он работает нормально, но когда я захватить изображение интерфейс замерзает в течение нескольких миллисекунд.

Почему диспетчер не работает на фоне, не затрагивая интерфейс?

+0

Это не имеет смысла называть 'Dispatcher.Invoke' в обработчике тике DispatcherTimer, так как метод обработчика уже вызываемый в потоке пользовательского интерфейса. Кроме того, Invoke не вызывает ничего в фоновом потоке. Это делается наоборот: если вы вызываете его из фонового потока, он вызывает действие в потоке пользовательского интерфейса. – Clemens

+0

Возможно, вы захотите назвать свой захватный код фоновым потоком (например, 'System.Threading.Timer') и вызвать' imageTelecamera.Source = src; 'в диспетчерском действии. Также неясно, что здесь должны делать «BeginInit» и «EndInit», поскольку вы, кажется, называете их в элементе управления Image, что совсем необязательно. – Clemens

ответ

0

Вашего непонимания того, что диспетчер является

диспетчер позволяет посылать команды в GUI поток, то это означает, что в то время как ваша команда выполнение GUI нить приостановлена ​​в ожидании его завершение.

Правильное использование диспетчера заключается в том, чтобы отправлять потоки конкретных задач в правильную нить для их выполнения, т. Е. Ваш элемент управления имеет список дочерних элементов, список можно редактировать безопасно только из элемента управления, поэтому, если вам нужно добавить или удалить ребенок вы используете средства управления диспетчером, чтобы получить контроль, чтобы выполнить добавление новой команды Item

здесь полный пример

XAML:

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:WpfApplication1" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 

    <DockPanel> 
     <Button x:Name="butStart" DockPanel.Dock="Top" Click="Button_Click">start</Button> 
     <TextBlock x:Name="output"/> 
    </DockPanel> 
</Window> 

код позади:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     timer.Interval = new TimeSpan(0, 0, 3); 
     timer.Tick += Timer_Tick; 
    } 

    private void Timer_Tick(object sender, EventArgs e) 
    { 
     //start taking photo 
     Task.Run(()=> TakePhoto()); 
    } 

    public DispatcherTimer timer { get; } = new DispatcherTimer(); 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     if(timer.IsEnabled) 
     { 
      timer.Stop(); 
      butStart.Content = "Start"; 

      //this works as you are in the main thread 
      output.Text += "Time Stopped" + Environment.NewLine; 
     } 
     else 
     { 
      timer.Start(); 
      butStart.Content = "Stop"; 
      output.Text += "Time Started" + Environment.NewLine; 
     } 
    } 
    public async void TakePhoto() 
    { 
     //with out the dispatcher this would error as you are not in the Gui thread so have no access to the Text property 
     output.Dispatcher.Invoke(()=>output.Text += "Take Photo" + Environment.NewLine); 
     //Simulate a long running task 
     await Task.Delay(5000); 
     output.Dispatcher.Invoke(()=>output.Text += "Take Photo - Complete" + Environment.NewLine); 
    } 
} 

теперь применяется к коду

private void DispatcherTimer_Tick(object sender, EventArgs evA) 
{ 
    Task.Run() => 
    { 
     try 
     { 
      BitmapFrame src; 
      var webRequest = (HttpWebRequest)WebRequest.Create(@"http://camera_ip/cgi-bin/video.cgi?msubmenu=jpg"); 
      webRequest.Credentials = new NetworkCredential("user", "password"); 
      webRequest.Proxy = null; 

      var response = (HttpWebResponse)webRequest.GetResponse(); 
      var stream = response.GetResponseStream(); 
      var streamReader = new StreamReader(stream); 
      src = BitmapFrame.Create(streamReader.BaseStream); 

      imageTelecamera.Dispatcher.Invoke(()=> 
      { 
       imageTelecamera.BeginInit();//not actually required 
       imageTelecamera.Source = src; 
       imageTelecamera.EndInit();//not actually required 
      }); 
      } 
     catch (Exception ex) 
     { 
      DoLogD($"Error: {ex.Message}"); 
     } 
    } 
    )); 
} 
+0

Я пробовал ваше предложение, но все равно получаю эти миллисекунды UI замерзания. Я начинаю думать, что проблема может заключаться в распределении ресурсов (WebRequest, Stream, StreamReader). – aDone

+0

, если ваша система борется за ресурсы там, я не могу многое сделать, подумал, что вы можете попробовать запустить код за пределами визуальной студии, поскольку VS - довольно свирепство, если вы загружаете изображения с высоким разрешением в источник изображения, что может вызвать проблема в том, что она должна обрабатывать и отображать изображение мгновенно, вы можете получить лучшую производительность из «BitmapImage», а не «BitmapFrame», поскольку изображение оптимизировано для загрузки фона – MikeT

 Смежные вопросы

  • Нет связанных вопросов^_^