Home c# multithreading in C # and WPF

multithreading in C # and WPF

Author

Date

Category

How to implement multithreading in WPF? You need to make a program that when you receive data on the COM port changes the video in the program to another, randomly selected from the available. The essence is to start a cycle in the second stream, which will read the data from the COM port and change the video in the program, because When I just enter the cycle, the program is simply stuck.

Here is my code:

optionswindow optionswindow;
  Serialport MyPort;
  INT TIMER;
  Public Mainwindow ()
  {
    Initializecomponent ();
    MyPort = New SerialPort ();
    playermediaelement.source = new uri (appdomain.currentDomain.basedirectory + @ "videos \ 0.mp4", urikind.absolute);
    playermediaelement.loadedbehavior = mediastate.manual;
    playermediaelement.unloadedbehavior = mediastate.Manual;
    playermediaelement.play ();
    Using (StreamReader SR = New StreamReader ("PortOptions.txt", Encoding.Default))
    {
      myport.portname = sr.ReadLine ();
      myport.baudrate = int.parse (sr.ReadLine ());
      Timer = int.parse (sr.ReadLine ());
    }
  }
  Private Void PlayermediaElement_MediaEnded (Object Sender, RouteDeventArgs E)
  {
    playermediaelement.stop ();
    playermediaelement.play ();
  }
  Private Void Window_Keydown (Object Sender, Keyeventargs E)
  {
    if (E.KEY == KEY.P)
    {
      optionswindow = new optionswindow ();
      optionswindow.show ();
    }
  }

You need to perform this feature in a new stream or asynchronously (the main thing that the program would not have stolen)

void testonnewlog ()
  {
    While (True)
    {
      if (myport.ReadLine ()! = NULL) MessageBox.Show ("New data came!");
    }
  }

I was looking for a material on this topic on the Internet, but did not help … if someone knows I ask to help


Answer 1, Authority 100%

By itself, the start of the stream is trivial task. As I already scaled, you can find examples in Documentation or just search on the Internet .

However, you must understand that in WPF there is the concept of the main UI stream and all interaction with the elements of the user interface should occur strictly through the UI stream.

The question arises: here you launched your code in the background stream, and you need to update something in the program interface. How to do it? To do this, there is a dispatcher. You can ask the dispatcher to execute the code in the UI stream.

How it works: for example, I will create a stream that considers up to 100, and the meter value will display:

Public Class Mywnd: Window
{
  Private TextBlock TB;
  Public MyWnd ()
  {
    TB = New TextBlock () {width = 300};
    TB.FontSize = 72;
    this.content = TB;
    this.sizetocontent = sizetocontent.widthandHeight;
    Var Thread = New Thread (Worker) {IsBackground = True};
    thread.start ();
  }
  Private Void Worker (Object State)
  {
    for (var i = 0; i & lt; 100; i ++)
    {
      var t = i.tostring ();
      this.dispatcher.invoke (() = & gt; {tb.text = t;});
      Thread.sleep (1000);
    }
  }
}

How to run

new mywnd (). Showdialog ();

result

It remains only to note that the approach described here works well on small applications, but if you write something more or less serious, then you should pay attention to MVVM Pattern.

Here’s an example. We define a simple command

public class DelegateCommand: ICommand
{
  Private Readonly Action & LT; Object & GT; _Execute;
  PRIVATE READONLY PREDICATE & LT; OBJECT & GT; _canexecute;
  public DelegateCommand (Action & lt; object & gt; execute, Predicate & lt; object & gt; canExecute = null)
  {
    _execute = execute;
    _canExecute = canExecute;
  }
  Public Bool Canexecute (Object Parameter)
  {
    return _canExecute? .Invoke (parameter) ?? true;
  }
  Public Void Execute (Object Parameter)
  {
    _execute.Invoke (parameter);
  }
  Public Event Eventhandler Canexecutechanged
  {
    add = & gt; CommandManager.RequerySuggest + = Value;
    REMOVE = & GT; Commandmanager.requerysuggested - = value;
  }
}

Our ViewModel will sodezhat value and all of flow control logic

public class MyViewModel: INotifyPropertyChanged
{
  public ICommand StartCommand {get; }
  public ICommand StopCommand {get; }
  private int _value;
  public int Value
  {
    get = & gt; _value;
    SET.
    {
      if (value == _value) return;
      _value = value;
      OnPropertyChanged ();
    }
  }
  private Thread _thread;
  private CancellationTokenSource _tokenSource;
  public MyViewModel ()
  {
    StartCommand = new DelegateCommand ((p) = & gt;
      {
        _tokenSource = new CancellationTokenSource ();
        _thread = new Thread (Worker) {IsBackground = true};
        _thread.Start (_tokenSource.Token);
      },
      p = & gt; _thread == null);
    StopCommand = new DelegateCommand (p = & gt;
    {
      _tokenSource.Cancel ();
      _tokenSource = null;
      _thread = null;
    }, P = & gt; _thread = null)!;
  }
  Private Void Worker (Object State)
  {
    var token = (CancellationToken) state;
    while (! token.IsCancellationRequested)
    {
      Value ++;
      Thread.sleep (1000);
    }
  }
  Public Event PropertyChangeDeventHandler PropertyChanged;
  [NotifyPropertyChangedInvocator]
  PROTECTED VIRTUAL VOID OnPropertyChanged ([CallermemberName] String PropertyName = NULL)
  {
    PropertyChanged? .Invoke (This, New PropertyChangeDeventargs (PropertyName));
  }
}

It’s simple – 2 teams to start and stop, and start / stop the flow.

Next, the idea here is to be

& lt; Window x: Class = "RU_1018395.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: RU_1018395"
      MC: IGNORABLE = "D"
      Title = "MainWindow" SizeToContent = "WidthAndHeight" & gt;
  & lt; window.resources & gt;
    & Lt; local: MyViewModel x: Key = "viewmodel" & gt; & lt; / local: MyViewModel & gt;
  & lt; /window.resources>
  & Lt; Grid DataContext = "{StaticResource viewmodel}" & gt;
    & lt; grid.columndefinitions & gt;
      & Lt; ColumnDefinition & gt; & lt; / ColumnDefinition & gt;
      & Lt; ColumnDefinition & gt; & lt; / ColumnDefinition & gt;
    & lt; /grid.columndefinitions>
    & Lt; StackPanel Orientation = "Vertical" Margin = "5" & gt;
      & Lt; Button Command = "{Binding StartCommand}" & gt; Start & lt; / Button & gt;
      & Lt; Button Command = "{Binding StopCommand}" & gt; Stop & lt; / Button & gt;
    & lt; / stackpanel & gt;
    & Lt; TextBlock FontSize = "72" Grid.Column = "1" Text = "{Binding Value}" & gt; & lt; / TextBlock & gt;
  & lt; / grid & gt;
& lt; / window & gt;

In the view I put ViewModel as a resource and then pulled the ViewModel to the grid.
By the way, you can see that I have not used a dispatcher anywhere – all because I use bindings to transfer data between the ViewModel and the View, and they already understand how to work with the UI thread.

Well, the result

On the one hand, it may seem that the second example is more complex, but in fact, we separated the logic from the presentation and avoided the mess that you have in the example in the main form constructor.

Programmers, Start Your Engines!

Why spend time searching for the correct question and then entering your answer when you can find it in a second? That's what CompuTicket is all about! Here you'll find thousands of questions and answers from hundreds of computer languages.

Recent questions