这个问题与以前类似的问题不同。我还没有从他们那里找到我的问题的答案。我正在运行2个线程。线程#2接收消息,从中解析数据并准备在Windows窗体GUI中显示。线程#1运行Windows窗体GUI显示并更新其中的文本框值。我在除SetOperations类之外的两个不同的类中创建了一个事件和事件处理程序。 SetOperations是我的表单所在的类。我的代码编译并运行没有错误。我的事件似乎触发,事件处理程序似乎接收数据。我的文本框参数值也似乎已分配。我的问题是,当事件处理程序结束时,我没有看到文本框值更新。
以下是精简代码片段。我希望它说明了如何在GUI显示的类之间传递消息数据。我是C#新手所以请原谅我的一些无知。有没有人有一个我忽略的建议?事件处理程序是否需要位于SetOperations类或其他位置才能更新文本框值?
感谢您提供任何人可以分享的建议。
static class Program
{
// The main entry point for the application.
[STAThread]
static void Main()
{
Aag_Listen AagListen1 = new Aag_Listen();
Trace.WriteLine("Application: Thread #1 and #2: about to start");
// starts Thread #2 where the Aag (server) listens for the Lru (client) message
Thread AagListenThread = new Thread(new ThreadStart(AagListen1.ListenForLru));
AagListenThread.Start();
while(!AagListenThread.IsAlive)
;
Thread.Sleep(3000);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new SetOperation()); // this runs in Thread #1
}
}
// Class is the beginning of Thread #2: Aag (server) listens for Lru (client) incoming message
// Gets the message data; calls to prepare it to be displayed by GUI; It then responds to the Lru
// 1) listens for the Lru msg, accesses and reads it into an object
// 2) passes the object with the message string to the AagPrepDisplay class
public class Aag_Listen
{
#region Fields
private Aag_Listen mAagListen2;
private string lruString;
internal Aag_PrepDisplay AagPrepDisplay; // need external access by Thread #1
#endregion Fields
#region Properties
public Aag_Listen AagListen2
{
get { return mAagListen2; }
set { mAagListen2 = value; }
}
public string LruString
{
get { return lruString; }
set { lruString = value; }
}
#endregion Properties
#region Methods
// Aag (server) begins to listen for a Lru (client) message
public void ListenForLru()
{
AagShowRequestData();
}
// Aag listener reads status of message data sent
public void AagShowRequestData()
{
mAagListen2 = new Aag_Listen();
this.AagPrepDisplay = new Aag_PrepDisplay();
// this simulates updating each channel with message data as received from the Lru (client)
int chan = 1;
while(true)
{
// display 405.1 and other message values
switch(chan)
{
case 1:
mAagListen2.LruString = "<tdrop><path sondeID=\"11024\"chanNum=\"1\"rxFreq=\"405.1\" />" +
"<sample frameNum=\"3440\"nsats=\"4\"gdop=\"25.5\"battery=\"5.58\"time=\"403892.500\"" +
"posx=\"-4738495.06\"posy=\"-2993107.15\"posz=\"-3044438.50\"gpsWeek=\"706\" /></tdrop>";
Trace.WriteLine("mAagListen2.LruString = " + mAagListen2.LruString);
chan = 3;
break;
case 2:
mAagListen2.LruString = "<tdrop><path sondeID=\"11024\"chanNum=\"3\"rxFreq=\"405.1\" />" +
"<sample frameNum=\"3440\"nsats=\"4\"gdop=\"25.5\"battery=\"5.58\"time=\"403892.500\"" +
"posx=\"-4738495.06\"posy=\"-2993107.15\"posz=\"-3044438.50\"gpsWeek=\"706\" /></tdrop>";
Trace.WriteLine("mAagListen2.LruString = " + mAagListen2.LruString);
chan = 4;
break;
default:
break;
}
}
AagPrepDisplay.PrepareDisplay(AagListen2); // prepares data for Windows Form GUI display
}
}
#endregion Methods
}
// Class runs in Thread #2: Aag (server) prepares received Lru (client) message data for Windows Form GUI display
// 1) receives from Aag_Listen class message and determines if it's a correct message
// 2) creates an object and extracts parameter values from message and assigns to object.
public class Aag_PrepDisplay
{
#region Fields
private string chanNum;
private string receiveFreq;
private DateTime date_time;
private static int first;
private static int last;
private Aag_PrepDisplay mAagPrep;
#endregion Fields
#region Properties
public Aag_PrepDisplay AagPrep
{
get { return mAagPrep; }
set { mAagPrep = value; }
}
}
public string ReceiveFreq
{
get { return receiveFreq; }
set { receiveFreq = value; }
}
public string ChanNum
{
get { return chanNum; }
set { chanNum = value; }
}
#endregion Properties
#region Methods
// begins extracting message parameters for Windows Form GUI display
public void PrepareDisplay(Aag_Listen aagListen2)
{
mAagPrep = new Aag_PrepDisplay();
Aag_DisplayEvent AagDisEvt1 = new Aag_DisplayEvent();
bool Tdrop = aagListen2.LruString.Contains("tdrop"); // search for correct message
if(!Tdrop) // reject string if not correct
return;
else
{ //search message data string for channel parameters to prepare for Aag display
// search for channel number from message; extract and save as string
first = aagListen2.LruString.IndexOf("chanNum=\"") + "chanNum=\"".Length;
last = aagListen2.LruString.IndexOf("\"rxFreq");
String substring = new String('1', 1);
mAagPrep.ChanNum = aagListen2.LruString.Substring(first, last - first);
Trace.WriteLine("mAagPrep.ChanNum = " + mAagPrep.ChanNum);
AagDisEvt1.ChDet += new ChDetHandler(OnChDetDisplay); // hooks handler to event
AagDisEvt1.ChDetDisplay(AagPrep); // passes the object w/message parameters to AagDisplayEvent class to fire the event
}
}
// event handler called from Aag_DisplayEvent class
public void OnChDetDisplay(object sender, ChanEventArg e)
{
SetOperation SetOp1 = new SetOperation();
SetOp1.updateAll(AagPrep);
} //******* PROBLEM HERE: WHY doesn't Windows Form actual frequency textbox update when this event closes? PROBLEM HERE:*********
#endregion Methods
}
// class handles the event argument that is the AagPrep class object containing all message parameters
public class ChanEventArg : EventArgs
{
public object Name;
public ChanEventArg(object name)
{
Name = name;
}
}
public delegate void ChDetHandler(object sender, ChanEventArg e); // declare delegate
// class is acting server that handles event notification
public class Aag_DisplayEvent
{
public event ChDetHandler ChDet; // delegate object reference declared
// helper method to help call delegate object for event
protected void OnChDet(ChanEventArg e)
{
if(ChDet != null)
{
ChDet(this, e); // calls event
}
}
// fires event by calling helper method
public void ChDetDisplay(object name)
{
OnChDet(new ChanEventArg(name));
}
}
// this class is the Windows Form running in Thread #1. It displays and updates all Window Form textboxes.
public partial class SetOperation : Form
{
public SetOperation()
{
Trace.WriteLine("Thread #1: Set Operations Launched");
InitializeComponent();
}
// updates the Aag (server) actual received frequency GUI display as received by the Lru (client) channel message
public void updateActFreq(Aag_PrepDisplay aagPrep)
{
Trace.WriteLine("Update Actual Frequency Selected");
switch(aagPrep.ChanNum)
{
case "1":
Trace.WriteLine("Update ActFreqChan1 Selected");
ActFreqChan1.Text = aagPrep.ReceiveFreq; // Lru (client) actual received frequency
break;
case "2":
Trace.WriteLine("Update ActFreqChan2 Selected");
ActFreqChan2.Text = aagPrep.ReceiveFreq;
break;
case "3":
Trace.WriteLine("Update ActFreqChan3 Selected");
ActFreqChan3.Text = aagPrep.ReceiveFreq; // PROBLEM: Why is this not updated in Windows Form textbox?
Trace.WriteLine("aagPrep.ReceiveFreq = " + aagPrep.ReceiveFreq);
Trace.WriteLine("ActFreqChan3.Text = " + ActFreqChan3.Text); // NOTE: this does reflect the updated actual frequency.
break;
default:
break;
}
}
// called from the Aag_DisplayEvent class event handler to update the actual frequency in Windows Form textboxes
public void updateAll(Aag_PrepDisplay aagPrep)
{
Trace.WriteLine("Update All Selected");
updateActFreq(aagPrep);
}
}
答案 0 :(得分:0)
您的问题与此主题的其他问题完全一样。将方法调用封送到UI线程有三种方法,虽然我没有详细阅读你的代码,但我不知道你在哪里使用它们。这就是问题所在。一种方法适用于WinForms表单或控件中的代码,一种适用于WPF窗口和控件,而第三种适用于无法直接访问控件的WinForms或WPF应用程序中的代码。我已经演示了所有三个here。在您的情况下实施最合适的。如果您希望表单或控件执行编组,那么使用ISynchronizeInvoke,如果您希望类在UI线程上引发事件,即使它不是UI元素本身,也请使用SynchronizationContext。