2009-04-02 15 views
8

Trong mẫu WPF của tôi, tôi có một hộp văn bản.
Khi bộ đếm thời gian trôi qua, nội dung của hộp văn bản cần được tìm nạp.
Bộ hẹn giờ trôi qua đang hoạt động trong một chuỗi khác rồi đến giao diện người dùng.Cách đọc giá trị textbox.Text từ một chuỗi khác trong WPF?

Câu hỏi đặt ra là kinda hai lần:

  • , cách dễ đọc nhất dễ nhất để đọc giá trị từ một sợi GUI chủ đề chéo là gì (tôi tìm thấy nhau và họ trông quá verbose cho những gì nên được một cái gì đó thực sự cơ bản)?
  • Tôi không thể đọc văn bản theo cách không bị chặn? Tôi không quan tâm về an toàn thread trong trường hợp này.

--EDIT--
tôi đã sử dụng Dispatcher, nhưng đã có một cuộc gọi dài dòng hơn thì những gì John thăm:

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

sẽ không quan tâm thậm chí terser mặc dù. Việc truy cập thuộc tính văn bản phải hoàn toàn cơ bản.

Trả lời

1

Không có "hack nhanh" để đọc giá trị của đối tượng GUI từ một chuỗi khác so với giá trị tạo ra nó. WPF sẽ không cho phép bạn làm tất cả. Windows Forms sẽ phàn nàn đôi khi, nhưng WPF là cách nghiêm ngặt hơn.

Bạn cần tìm hiểu về Người điều phối. Nó có thể trông dài dòng, nhưng nó thực sự không phải là khó hiểu. Bạn chuyển giao một ủy nhiệm cho người điều phối trỏ đến một phương thức mà bạn muốn được gọi trên luồng GUI, và nó thực hiện nó.

Dưới đây là một ví dụ đơn giản đẹp:

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

+1

Vì vậy, không có cách gọi giá trị nào không an toàn sau đó? Tôi chỉ cần nhận được nó, không đặt nó. –

+0

Tôi không thực sự tìm kiếm một hack nhanh chóng, tôi đang tìm kiếm một cái gì đó có thể đọc được. Một bàn tay ngắn nếu bạn muốn. –

+0

xin lỗi để phá vỡ bong bóng của bạn, nhưng bằng cách sử dụng dispatcher IS viết tắt. :) bạn muốn viết dispatcher/marshaller của riêng bạn? – x0n

5

Oisin là đúng, bạn cần phải nhìn vào Dispatcher. Một cái gì đó như thế này nên làm việc, và không phải là quá dài dòng:

System.Windows.Application.Current.Dispatcher.Invoke(
DispatcherPriority.Normal, 
(ThreadStart)delegate { text = MyTextBox.Text; }); 
+0

Vâng nó tốt hơn thì những gì tôi có originalTextBox.Dispatcher.Invoke ( DispatcherPriority.Normal, hành động mới ( đại biểu() { text = originalTextBox.Text; })); –

5

Bạn có thể:

  • Sử dụng Dispatcher để sắp xếp một thông điệp tới thực hiện trên thread UI từ một sợi nền. A DispatcherPriority của Send sẽ giúp bạn có được phản hồi nhanh nhất có thể.
  • Sử dụng DispatcherTimer để thực thi định kỳ thư trên chuỗi giao diện người dùng.
  • Sử dụng liên kết OneWayToSource để kết nối thuộc tính Text với thuộc tính trên thành phần nền của bạn. Bằng cách đó, bạn sẽ không phải thực hiện bất kỳ công việc nào để nhận giá trị thuộc tính - nó sẽ được cung cấp cho thành phần của bạn.
0

solutiosn của tôi ... Các 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> 

và File 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; }); 
    } 



} 

hộp văn bản thứ hai là cho một thử nghiệm loại trong khi thread là runing

1

câu trả lời khác là sử dụng Jeff Lớp SmartDispatcher của Wilcox.

Một nơi nào đó trong trường hợp nhà xây dựng hoặc tải làm một SmartDispatcher.Initialize() (để thiết lập các điều phối UI)

Sau đó, bất cứ nơi nào bạn cần phải thiết lập một tài sản hoặc gọi một phương thức:

Action a = delegate { <statements> }; 
SmartDispatcher.BeginInvoke(a); 

Các vẻ đẹp của điều này là bạn không cần phải biết liệu nó có nằm trong chuỗi giao diện người dùng hay không (và bạn có thể cần phải làm điều đó từ cả hai). SmartDispatcher sẽ xử lý công tắc chủ đề nếu cần.

Ở trên là không đồng bộ, nhưng nếu bạn cần đồng bộ, chỉ cần thêm phương thức khác để gọi Gọi thay vì BeginInvoke.

1

Chỉ xảy ra vấp ngã vào đây. Một thời gian trở lại tôi chỉ mới bắt đầu xây dựng một lớp tĩnh mà tôi có thể thêm vào các dự án của mình để truy cập nhanh vào một số thuộc tính điều khiển chung. Nó cồng kềnh theo thời gian nhưng làm cho mọi việc trở nên dễ dàng trong khi ẩn đi rất nhiều mã điều phối. Thô lỗ nhưng hiệu quả. Có thể cung cấp cho bạn một số ý tưởng. tôi về cơ bản có thể làm những việc như thế này:

string temp = SafeGuiWpf.GetText(originalTextBox); 

Dưới đây là những gì các SafeGuiWpf cuối cùng trông giống như, nếu bạn thấy nó hữu ích. (Hãy nghĩ rằng nó hoạt động trong NET 3 trở lên, nhưng nó đã được một thời gian)

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 

Nhìn lại, có thể làm cho chúng thậm chí còn trơn tru hơn nếu tôi đã làm như là mở rộng lớp.

1

tôi sử dụng phương pháp mở rộng sau đây để làm được việc này:

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; 
     } 
    } 

Và dĩ nhiên, phương pháp này đã được thêm vào trong một lớp tĩnh riêng biệt.

+1

Tuyệt vời! Giải pháp thực sự tuyệt vời! Tôi đã áp dụng nó trong dự án WinForm của tôi (tôi đã làm cho nó mặc dù chung chung)! Nó hoạt động tuyệt vời! –

Các vấn đề liên quan