이 질문에는 이미 답변이 있습니다.
UART를 사용하여 마이크로 컨트롤러에서 온도 값을 C #인터페이스로 보내고 온도를 표시하고 싶습니다.Label.Content
. 여기 내 마이크로 컨트롤러 코드 :
while(1) {
key_scan(); // get value of temp
if (Usart_Data_Ready())
{
while(temperature[i]!=0)
{
if(temperature[i]!=' ')
{
Usart_Write(temperature[i]);
Delay_ms(1000);
}
i = i + 1;
}
i =0;
Delay_ms(2000);
}
}
내 C #코드는 다음과 같습니다.
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
txt += serialPort1.ReadExisting().ToString();
textBox1.Text = txt.ToString();
}
그러나 예외는 거기에서 일어난다 "크로스 스레드 작업이 유효하지 않습니다 : 'textBox1'이 (가) 생성 된 스레드가 아닌 다른 스레드에서 액세스 제어" 제 마이크로 컨트롤러에서 온도 스트링을 얻는 방법을 알려주고이 에러를 제거하십시오!
받은 데이터serialPort1_DataReceived
메서드가 UI 스레드가 아닌 다른 스레드 컨텍스트에서오고 있기 때문에이 오류가 표시됩니다.
이 문제를 해결하려면 MSDN 문서에서 설명한대로 디스패처를 사용해야합니다.
방법 : Windows Forms 컨트롤에 스레드 안전 호출 만들기
따라서 텍스트 속성을 직접serialport1_DataReceived
메소드에서이 패턴을 사용하십시오.
delegate void SetTextCallback(string text);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
따라서 귀하의 경우 :
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
txt += serialPort1.ReadExisting().ToString();
SetText(txt.ToString());
}
if (this.InvokeRequired) { //SetTextCallBack etc. }
대신에if (this.textBox1.InvokeRequired) { //SetTextCallBack etc. }
- Jroonkcontrol.BeginInvoke
너무 일해? 해결책은 이것 같이 1 개의 선 너무 일 수있다, 맞은?textbox1.BeginInvoke((MethodInvoker)delegate(){ textbox1.Text = txt.ToString(); });
- newbieguySetTextCallback
호출하기 위해 노력한다.SetText
네가 지나가는거야.SetText
에new SetTextCallback()
. DUHHH - ErikE
이게 충분히 좋은지 모르겠지만 정적 ThreadHelperClass 클래스를 만들고 다음과 같이 구현했습니다. 이제 많은 코딩없이 다양한 컨트롤의 텍스트 속성을 쉽게 설정할 수 있습니다.
public static class ThreadHelperClass
{
delegate void SetTextCallback(Form f, Control ctrl, string text);
/// <summary>
/// Set text property of various controls
/// </summary>
/// <param name="form">The calling form</param>
/// <param name="ctrl"></param>
/// <param name="text"></param>
public static void SetText(Form form, Control ctrl, string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (ctrl.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
form.Invoke(d, new object[] { form, ctrl, text });
}
else
{
ctrl.Text = text;
}
}
}
코드 사용 :
private void btnTestThread_Click(object sender, EventArgs e)
{
Thread demoThread =
new Thread(new ThreadStart(this.ThreadProcSafe));
demoThread.Start();
}
// This method is executed on the worker thread and makes
// a thread-safe call on the TextBox control.
private void ThreadProcSafe()
{
ThreadHelperClass.SetText(this, textBox1, "This text was set safely.");
ThreadHelperClass.SetText(this, textBox2, "another text was set safely.");
}
That's awesome solution
, 가장 멋진 것은"it's open for extension and generic"
. 원하는대로 새 UI 업데이트 기능을 추가 할 수 있습니다. 감사합니다. - Basheer AL-MOMANI
당신은 단순히 이것을 할 수 있습니다.
TextBox.CheckForIllegalCrossThreadCalls = false;
다음 확장명을 사용하고 다음과 같은 동작을 전달하십시오.
_frmx.PerformSafely(() => _frmx.Show());
_frmx.PerformSafely(() => _frmx.Location = new Point(x,y));
확장 클래스 :
public static class CrossThreadExtensions
{
public static void PerformSafely(this Control target, Action action)
{
if (target.InvokeRequired)
{
target.Invoke(action);
}
else
{
action();
}
}
public static void PerformSafely<T1>(this Control target, Action<T1> action,T1 parameter)
{
if (target.InvokeRequired)
{
target.Invoke(action, parameter);
}
else
{
action(parameter);
}
}
public static void PerformSafely<T1,T2>(this Control target, Action<T1,T2> action, T1 p1,T2 p2)
{
if (target.InvokeRequired)
{
target.Invoke(action, p1,p2);
}
else
{
action(p1,p2);
}
}
}
이전 답변과 동일한 줄에 따라, 매우 짧은 추가로 크로스 스레드 인보 케이션 예외없이 모든 컨트롤 속성을 사용할 수 있습니다.
도우미 방법
/// <summary>
/// Helper method to determin if invoke required, if so will rerun method on correct thread.
/// if not do nothing.
/// </summary>
/// <param name="c">Control that might require invoking</param>
/// <param name="a">action to preform on control thread if so.</param>
/// <returns>true if invoke required</returns>
public bool ControlInvokeRequired(Control c,Action a)
{
if (c.InvokeRequired) c.Invoke(new MethodInvoker(delegate { a(); }));
else return false;
return true;
}
샘플 사용법
// usage on textbox
public void UpdateTextBox1(String text)
{
//Check if invoke requied if so return - as i will be recalled in correct thread
if (ControlInvokeRequired(textBox1, () => UpdateTextBox1(text))) return;
textBox1.Text = ellapsed;
}
//Or any control
public void UpdateControl(Color c,String s)
{
//Check if invoke requied if so return - as i will be recalled in correct thread
if (ControlInvokeRequired(myControl, () => UpdateControl(c,s))) return;
myControl.Text = s;
myControl.BackColor = c;
}
공유 컨테이너를 사용하여 스레드간에 데이터를 전송하십시오.