.net 如何从WPF中的另一个线程读取textbox.Text值?

.net 如何从WPF中的另一个线程读取textbox.Text值?,.net,wpf,multithreading,.net,Wpf,Multithreading,在我的WPF表单中,我有一个文本框。 计时器过期时,需要提取文本框的内容。 计时器运行在与UI不同的线程中 问题有两个方面: 从GUI线程跨线程读取值的最简单、最可读的方法是什么(我发现了几种,它们看起来太冗长了,不适合真正基本的东西) 我不能以非阻塞方式阅读课文吗?在这种情况下,我不关心线程安全 --编辑-- 我使用了Dispatcher,但有一个比它更详细的调用: 不过我不介意说得再简短些。访问文本属性应该是非常基本的。从创建GUI对象的线程以外的线程读取GUI对象的值没有“快速破解”的

在我的WPF表单中,我有一个文本框。
计时器过期时,需要提取文本框的内容。
计时器运行在与UI不同的线程中

问题有两个方面:

  • 从GUI线程跨线程读取值的最简单、最可读的方法是什么(我发现了几种,它们看起来太冗长了,不适合真正基本的东西)
  • 我不能以非阻塞方式阅读课文吗?在这种情况下,我不关心线程安全
--编辑--
我使用了Dispatcher,但有一个比它更详细的调用:

不过我不介意说得再简短些。访问文本属性应该是非常基本的。

从创建GUI对象的线程以外的线程读取GUI对象的值没有“快速破解”的方法。WPF不会允许你做所有的事情。Windows窗体有时会抱怨,但WPF要严格得多

您需要了解调度程序。这可能看起来很冗长,但其实并不难理解。您将一个委托传递给调度程序,该调度程序指向您希望在GUI线程上调用的方法,并且它会这样做

下面是一个很好的简单示例:


奥辛是对的,你需要看看。这样的方法应该可以,而且不会太冗长:

System.Windows.Application.Current.Dispatcher.Invoke(
DispatcherPriority.Normal,
(ThreadStart)delegate { text = MyTextBox.Text; });
您可以:

  • 使用调度消息以从后台线程在UI线程上执行。一次
    发送
    将使您获得尽可能快的响应
  • 使用来定期在UI线程上执行消息
  • 使用
    OneWayToSource
    绑定将
    Text
    属性连接到后台组件上的属性。这样,您就不必做任何工作来获取属性值——它已经提供给您的组件
    • 我的解决方案。。。 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>
      
      
      按钮
      

      和cs文件:

      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; });
          }
      
      
      
      }
      
      公共部分类窗口1:窗口
      {
      公共窗口1()
      {
      初始化组件();
      }
      私有无效按钮1\u单击(对象发送者,路由目标)
      {
      新系统.Threading.Thread(this.Cuenta.Start();
      }
      私人void Cuenta()
      {
      对于(int i=0;i<100000;i++)
      SetValues(string.Format(“Counting…{0}”,i));
      }
      私有void集合值(字符串str)
      {
      System.Windows.Application.Current.Dispatcher.Invoke(
      System.Windows.Threading.DispatcherPriority.Normal,
      (System.Threading.ThreadStart)委托{textBox1.Text=str;});
      }
      }
      

      第二个文本框用于线程运行时的类型测试,另一个答案是使用Jeff Wilcox的SmartDispatcher类

      在构造函数或加载事件中的某个位置执行SmartDispatcher.Initialize()(设置UI调度程序)

      然后,在需要设置属性或调用方法的任何位置:

      Action a = delegate { <statements> };
      SmartDispatcher.BeginInvoke(a);
      
      动作a=委托{};
      SmartDispatcher.BeginInvoke(a);
      
      这样做的好处是,您不需要知道它是否在UI线程上(并且您可能需要从这两个线程中都知道)。如有必要,SmartDispatcher会处理线程开关


      以上内容是异步的,但如果需要同步,只需添加另一个方法来调用Invoke,而不是BeginInvoke。

      只是碰巧进入了这里。不久前,我刚刚开始构建一个静态类,我可以将它添加到我的项目中,以便快速访问一些常见的控件属性。随着时间的推移,它会变得臃肿,但在隐藏大量调度程序代码的同时使事情变得非常简单。粗糙但有效。可能会给你一些想法。 我基本上可以这样做:

      string temp = SafeGuiWpf.GetText(originalTextBox);
      
      如果您觉得SafeGuiWpf有帮助的话,下面是它上次的样子。(认为它在NET3及以上版本中有效,但已经有一段时间了)

      使用系统;
      使用System.Collections.Generic;
      使用System.Linq;
      使用系统文本;
      使用System.Windows;
      使用System.Windows.Controls;
      使用System.Windows.Controls.Primitives;
      使用系统组件模型;
      公共类SafeGuiWpf
      {
      公共静态对象GetTag(控件C)
      {
      if(C.Dispatcher.CheckAccess())返回C.Tag;
      否则返回C.Dispatcher.Invoke(newfunc(GetTag),C);
      }
      公共静态字符串GetText(文本框TB)
      {
      if(TB.Dispatcher.CheckAccess())返回TB.Text;
      else返回(字符串)TB.Dispatcher.Invoke(newfunc(GetText),TB);
      }
      公共静态字符串GetText(组合框TB)
      {
      if(TB.Dispatcher.CheckAccess())返回TB.Text;
      else返回(字符串)TB.Dispatcher.Invoke(newfunc(GetText),TB);
      }
      公共静态字符串GetText(密码箱TB)
      {
      if(TB.Dispatcher.CheckAccess())返回TB.Password;
      else返回(字符串)TB.Dispatcher.Invoke(newfunc(GetText),TB);
      }
      公共静态void SetText(TextBlock TB,string Str)
      {
      如果(TB.Dispatcher.CheckAccess())TB.Text=Str;
      else TB.Dispatcher.Invoke(新操作(SetText)、TB、Str);
      }
      公共静态void SetText(文本框TB,字符串Str)
      {
      如果(TB.Dispatcher.CheckAccess())TB.Text=Str;
      else TB.Dispatcher.Invoke(新操作(SetText)、TB、Str);
      }
      公共静态无效文本(文本框TB,字符串Str)
      {
      if(TB.Dispatcher.CheckAccess())
      {
      TB.追加文本(Str);
      TB.ScrollToEnd();//是否滚动到末尾?
      }
      else TB.Dispatcher.Invoke(新操作(AppendText)、TB、Str);
      }
      公共静态bool?已选中(复选框Ck)
      {
      if(Ck.Dispatcher.CheckAccess())返回Ck.IsChecked;
      else返回(bool?)Ck.Dispatcher.Invoke(newfunc(GetChecked),Ck);
      }
      公共静态无效设置选中(复选框Ck,bool?V)
      {
      如果(Ck.Dispatcher.CheckAccess())Ck.IsChecked=V;
      else Ck.Dispatcher.Invoke(新操作(SetChecked),Ck,V);
      }
      公共静态bool GetChecked(菜单项Ck)
      {
      if(Ck.Dispatcher.CheckAccess())返回Ck
      
      string temp = SafeGuiWpf.GetText(originalTextBox);
      
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Windows;
      using System.Windows.Controls;
      using System.Windows.Controls.Primitives;
      using System.ComponentModel;
      
      public class SafeGuiWpf
      {
          public static object GetTag(Control C)
          {
              if (C.Dispatcher.CheckAccess()) return C.Tag;
              else return C.Dispatcher.Invoke(new Func<Control, object>(GetTag), C);
          }
          public static string GetText(TextBox TB)
          {
              if (TB.Dispatcher.CheckAccess()) return TB.Text;
              else return (string)TB.Dispatcher.Invoke(new Func<TextBox,string>(GetText), TB);
          }
          public static string GetText(ComboBox TB)
          {
              if (TB.Dispatcher.CheckAccess()) return TB.Text;
              else return (string)TB.Dispatcher.Invoke(new Func<ComboBox,string>(GetText), TB);
          }
      
          public static string GetText(PasswordBox TB)
          {
              if (TB.Dispatcher.CheckAccess()) return TB.Password;
              else return (string)TB.Dispatcher.Invoke(new Func<PasswordBox, string>(GetText), TB);
          }
      
          public static void SetText(TextBlock TB, string Str)
          {
              if (TB.Dispatcher.CheckAccess()) TB.Text = Str;
              else TB.Dispatcher.Invoke(new Action<TextBlock,string>(SetText), TB, Str);
          }
          public static void SetText(TextBox TB, string Str)
          {
              if (TB.Dispatcher.CheckAccess()) TB.Text = Str;
              else TB.Dispatcher.Invoke(new Action<TextBox, string>(SetText), TB, Str);
          }
          public static void AppendText(TextBox TB, string Str)
          {
              if (TB.Dispatcher.CheckAccess())
              {
                  TB.AppendText(Str);
                  TB.ScrollToEnd(); // scroll to end?
              }
              else TB.Dispatcher.Invoke(new Action<TextBox, string>(AppendText), TB, Str);
          }
          public static bool? GetChecked(CheckBox Ck)
          {
              if (Ck.Dispatcher.CheckAccess()) return Ck.IsChecked;
              else return (bool?)Ck.Dispatcher.Invoke(new Func<CheckBox,bool?>(GetChecked), Ck);
          }
          public static void SetChecked(CheckBox Ck, bool? V)
          {
              if (Ck.Dispatcher.CheckAccess()) Ck.IsChecked = V;
              else Ck.Dispatcher.Invoke(new Action<CheckBox, bool?>(SetChecked), Ck, V);
          }
          public static bool GetChecked(MenuItem Ck)
          {
              if (Ck.Dispatcher.CheckAccess()) return Ck.IsChecked;
              else return (bool)Ck.Dispatcher.Invoke(new Func<MenuItem, bool>(GetChecked), Ck);
          }
          public static void SetChecked(MenuItem Ck, bool V)
          {
              if (Ck.Dispatcher.CheckAccess()) Ck.IsChecked = V;
              else Ck.Dispatcher.Invoke(new Action<MenuItem, bool>(SetChecked), Ck, V);
          }
          public static bool? GetChecked(RadioButton Ck)
          {
              if (Ck.Dispatcher.CheckAccess()) return Ck.IsChecked;
              else return (bool?)Ck.Dispatcher.Invoke(new Func<RadioButton, bool?>(GetChecked), Ck);
          }
          public static void SetChecked(RadioButton Ck, bool? V)
          {
              if (Ck.Dispatcher.CheckAccess()) Ck.IsChecked = V;
              else Ck.Dispatcher.Invoke(new Action<RadioButton, bool?>(SetChecked), Ck, V);
          }
      
          public static void SetVisible(UIElement Emt, Visibility V)
          {
              if (Emt.Dispatcher.CheckAccess()) Emt.Visibility = V;
              else Emt.Dispatcher.Invoke(new Action<UIElement, Visibility>(SetVisible), Emt, V);
          }
          public static Visibility GetVisible(UIElement Emt)
          {
              if (Emt.Dispatcher.CheckAccess()) return Emt.Visibility;
              else return (Visibility)Emt.Dispatcher.Invoke(new Func<UIElement, Visibility>(GetVisible), Emt);
          }
          public static bool GetEnabled(UIElement Emt)
          {
              if (Emt.Dispatcher.CheckAccess()) return Emt.IsEnabled;
              else return (bool)Emt.Dispatcher.Invoke(new Func<UIElement, bool>(GetEnabled), Emt);
          }
          public static void SetEnabled(UIElement Emt, bool V)
          {
              if (Emt.Dispatcher.CheckAccess()) Emt.IsEnabled = V;
              else Emt.Dispatcher.Invoke(new Action<UIElement, bool>(SetEnabled), Emt, V);
          }
      
          public static void SetSelectedItem(Selector Ic, object Selected)
          {
              if (Ic.Dispatcher.CheckAccess()) Ic.SelectedItem = Selected;
              else Ic.Dispatcher.Invoke(new Action<Selector, object>(SetSelectedItem), Ic, Selected);
          }
          public static object GetSelectedItem(Selector Ic)
          {
              if (Ic.Dispatcher.CheckAccess()) return Ic.SelectedItem;
              else return Ic.Dispatcher.Invoke(new Func<Selector, object>(GetSelectedItem), Ic);
          }
          public static int GetSelectedIndex(Selector Ic)
          {
              if (Ic.Dispatcher.CheckAccess()) return Ic.SelectedIndex;
              else return (int)Ic.Dispatcher.Invoke(new Func<Selector, int>(GetSelectedIndex), Ic);
          }
      
          delegate MessageBoxResult MsgBoxDelegate(Window owner, string text, string caption, MessageBoxButton button, MessageBoxImage icon);
          public static MessageBoxResult MsgBox(Window owner, string text, string caption, MessageBoxButton button, MessageBoxImage icon)
          {
              if (owner.Dispatcher.CheckAccess()) return MessageBox.Show(owner, text, caption, button, icon);
              else return (MessageBoxResult)owner.Dispatcher.Invoke(new MsgBoxDelegate(MsgBox), owner, text, caption, button, icon);
          }
      
          public static double GetRangeValue(RangeBase RngBse)
          {
              if (RngBse.Dispatcher.CheckAccess()) return RngBse.Value;
              else return (double)RngBse.Dispatcher.Invoke(new Func<RangeBase, double>(GetRangeValue), RngBse);
          }
          public static void SetRangeValue(RangeBase RngBse, double V)
          {
              if (RngBse.Dispatcher.CheckAccess()) RngBse.Value = V;
              else RngBse.Dispatcher.Invoke(new Action<RangeBase, double>(SetRangeValue), RngBse, V);
          }
      
          public static T CreateWindow<T>(Window Owner) where T : Window, new()
          {
              if (Owner.Dispatcher.CheckAccess())
              {
                  var Win = new T(); // Window created on GUI thread
                  Win.Owner = Owner;
                  return Win;
              }
              else return (T)Owner.Dispatcher.Invoke(new Func<Window, T>(CreateWindow<T>), Owner);
          }
      
          public static bool? ShowDialog(Window Dialog)
          {
              if (Dialog.Dispatcher.CheckAccess()) return Dialog.ShowDialog();
              else return (bool?)Dialog.Dispatcher.Invoke(new Func<Window, bool?>(ShowDialog), Dialog);
          }
      
          public static void SetDialogResult(Window Dialog, bool? Result)
          {
              if (Dialog.Dispatcher.CheckAccess()) Dialog.DialogResult = Result;
              else Dialog.Dispatcher.Invoke(new Action<Window, bool?>(SetDialogResult), Dialog, Result);
          }
      
          public static Window GetWindowOwner(Window window)
          {
              if (window.Dispatcher.CheckAccess()) return window.Owner;
              else return (Window)window.Dispatcher.Invoke(new Func<Window, Window>(GetWindowOwner), window);
          }
      
      } // END CLASS: SafeGuiWpf
      
          public static string GetTextThreadSafely(this TextBoxBase source)
          {
              if (source.InvokeRequired)
              {
                  var text = String.Empty;
                  source.Invoke((Action)(() => { text = source.GetTextThreadSafely(); }));
                  return text;
              }
              else
              {
                  return source.Text;
              }
          }
      
      text = originalTextBox.Dispatcher.Invoke(Function() As String
          Return originalTextBox.Text
        End Function)