views:

1073

answers:

4

In my WPF form I have a textbox.
When a timer elapses, the content of the textbox needs to be fetched.
The timer elapsed is working in a different thread then the UI.

The question is kinda two-fold:

  • What is the easiest, most readable way to read the value from a GUI thread cross thread (I found several and they look too verbose for what should be something really basic)?
  • Can't I read the text in a non-blocking way? I don't care about thread safety in this case.

--EDIT--
I used the Dispatcher, but had a more verbose call then what John had:

originalTextBox.Dispatcher.Invoke(
    DispatcherPriority.Normal, 
    (ThreadStart) delegate{text=originalTextBox.Text;}
);

Wouldn't mind even terser though. Accessing a text property should be utterly basic.

+1  A: 

There is no "quick hack" for reading a GUI object's values from a differing thread than the one that created it. WPF will just not allow you to do it all. Windows Forms would complain occassionally, but WPF is way more strict.

You need to learn about the Dispatcher. It might look verbose, but it really isn't that hard to understand. You pass a delegate to the dispatcher that points to a method you want called on the GUI thread, and it does it.

Here's a nice simple example:

http://www.switchonthecode.com/tutorials/working-with-the-wpf-dispatcher

-Oisin

x0n
So no way of calling the value thread-unsafe then? I only need to get it, not set it.
borisCallens
I'm not really looking for a quick hack, I'm looking for something readable. A short hand if you will.
borisCallens
sorry to burst your bubble, but using the dispatcher IS shorthand. :) you want to write your own dispatcher/marshaller?
x0n
A: 

Oisin is right, you need to look at Dispatcher. Something like this should work, and is not too verbose:

System.Windows.Application.Current.Dispatcher.Invoke(
DispatcherPriority.Normal,
(ThreadStart)delegate { text = MyTextBox.Text; });
John Myczek
Well it's better then what I had originalTextBox.Dispatcher.Invoke( DispatcherPriority.Normal, new Action( delegate() { text = originalTextBox.Text; }));
borisCallens
+2  A: 

You can either:

  • Use the Dispatcher to schedule a message to execute on the UI thread from a background thread. A DispatcherPriority of Send will get you the fastest response possible.
  • Use a DispatcherTimer to periodically execute messages on the UI thread.
  • Use a OneWayToSource binding to connect the Text property to a property on your background component. That way, you won't have to do any work to get the property value - it will already have been supplied to your component.

HTH, Kent

Kent Boogaart
A: 

My solutiosn... The XAML:

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
    <TextBox Height="23" Margin="28,27,130,0" Name="textBox1" VerticalAlignment="Top" />
    <Button Height="23" HorizontalAlignment="Left" Margin="28,56,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click">Button</Button>
    <TextBox Margin="34,85,12,54" Name="textBox2" />
</Grid>

and the cs File:

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        new System.Threading.Thread(this.Cuenta).Start();
    }


    private void Cuenta()
    {
        for (int i = 0; i < 100000; i++)
            this.SetValues(string.Format("Counting... {0} ", i));
    }

    private void SetValues(string str)
    {
        System.Windows.Application.Current.Dispatcher.Invoke(
            System.Windows.Threading.DispatcherPriority.Normal,
            (System.Threading.ThreadStart)delegate { textBox1.Text = str; });
    }



}

the second textbox is for a type test while the thread is runing

a52