이벤트 중심 GUI 코드에서 다음 코드 패턴을 얼마나 자주 작성해야하는지 알고 있습니다.
private void DoGUISwitch() {
// cruisin for a bruisin' through exception city
object1.Visible = true;
object2.Visible = false;
}
된다 :
private void DoGUISwitch() {
if (object1.InvokeRequired) {
object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
} else {
object1.Visible = true;
object2.Visible = false;
}
}
이것은 C #에서 기억하기 쉽고 입력하기에 불편한 패턴입니다. 누구든지 이것을 어느 정도까지 자동화하는 일종의 지름길이나 구성을 생각해 냈습니까? object1.InvokeIfNecessary.visible = true
유형 바로 가기 와 같이이 모든 추가 작업을 거치지 않고이 검사를 수행하는 객체에 함수를 첨부하는 방법이 있다면 멋질 것 입니다.
이전 답변 에서는 매번 Invoke ()를 호출하는 것의 비현실성에 대해 논의했으며, 심지어 Invoke () 구문도 비효율적이며 여전히 다루기가 어려워졌습니다.
그래서 지름길을 알아 낸 사람이 있습니까?
답변
이의 접근 방식은 더 단순화 될 수있다
public static void InvokeIfRequired(this Control control, MethodInvoker action)
{
// See Update 2 for edits Mike de Klerk suggests to insert here.
if (control.InvokeRequired) {
control.Invoke(action);
} else {
action();
}
}
그리고 이렇게 불릴 수 있습니다
richEditControl1.InvokeIfRequired(() =>
{
// Do anything you want with the control here
richEditControl1.RtfText = value;
RtfHelpers.AddMissingStyles(richEditControl1);
});
컨트롤을 매개 변수로 대리자에게 전달할 필요가 없습니다. C #은 자동으로 클로저를 생성합니다 .
업데이트 :
다른 여러 포스터에 따르면 다음 Control
과 같이 일반화 할 수 있습니다 ISynchronizeInvoke
.
public static void InvokeIfRequired(this ISynchronizeInvoke obj,
MethodInvoker action)
{
if (obj.InvokeRequired) {
var args = new object[0];
obj.Invoke(action, args);
} else {
action();
}
}
DonBoitnott는 달리 지적 인터페이스의 오브젝트 배열 필요 위한 파라미터리스트로서 방법 .Control
ISynchronizeInvoke
Invoke
action
업데이트 2
Mike de Klerk가 제안한 편집 (삽입 점은 첫 번째 코드 스 니펫의 주석 참조) :
// When the form, thus the control, isn't visible yet, InvokeRequired returns false,
// resulting still in a cross-thread exception.
while (!control.Visible)
{
System.Threading.Thread.Sleep(50);
}
이 제안에 대한 우려는 아래 ToolmakerSteve의 의견을 참조하십시오.
답변
확장 방법을 작성할 수 있습니다.
public static void InvokeIfRequired(this Control c, Action<Control> action)
{
if(c.InvokeRequired)
{
c.Invoke(new Action(() => action(c)));
}
else
{
action(c);
}
}
그리고 이것을 다음과 같이 사용하십시오 :
object1.InvokeIfRequired(c => { c.Visible = true; });
편집 : Simpzon이 주석에서 지적한 것처럼 서명을 다음과 같이 변경할 수도 있습니다.
public static void InvokeIfRequired<T>(this T c, Action<T> action)
where T : Control
답변
다음은 모든 코드에서 사용한 양식입니다.
private void DoGUISwitch()
{
Invoke( ( MethodInvoker ) delegate {
object1.Visible = true;
object2.Visible = false;
});
}
나는 블로그 항목 here을 기반으로했습니다 . 나는이 접근법이 실패하지 않았으므로 InvokeRequired
속성을 확인하여 코드를 복잡하게 만들 이유가 없습니다 .
도움이 되었기를 바랍니다.
답변
ThreadSafeInvoke.snippet 파일을 만든 다음 업데이트 명령문을 선택하고 마우스 오른쪽 단추를 클릭 한 후 ‘Surround With …’또는 Ctrl-K + S를 선택하십시오.
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<Header>
<Title>ThreadsafeInvoke</Title>
<Shortcut></Shortcut>
<Description>Wraps code in an anonymous method passed to Invoke for Thread safety.</Description>
<SnippetTypes>
<SnippetType>SurroundsWith</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Code Language="CSharp">
<![CDATA[
Invoke( (MethodInvoker) delegate
{
$selected$
});
]]>
</Code>
</Snippet>
</CodeSnippet>
답변
다음은 Lee ‘s, Oliver ‘s 및 Stephan ‘s의 개선 / 결합 버전입니다.
public delegate void InvokeIfRequiredDelegate<T>(T obj)
where T : ISynchronizeInvoke;
public static void InvokeIfRequired<T>(this T obj, InvokeIfRequiredDelegate<T> action)
where T : ISynchronizeInvoke
{
if (obj.InvokeRequired)
{
obj.Invoke(action, new object[] { obj });
}
else
{
action(obj);
}
}
이 템플릿을 사용하면 유연하고 캐스트가없는 코드를 사용할 수있어 훨씬 더 읽기 쉽고 전용 대리인이 효율성을 제공합니다.
progressBar1.InvokeIfRequired(o =>
{
o.Style = ProgressBarStyle.Marquee;
o.MarqueeAnimationSpeed = 40;
});
답변
매번 새 인스턴스를 만드는 대신 Delegate 메서드의 단일 인스턴스를 사용하고 싶습니다. 필자의 경우 Backroundworker의 진행 및 (정보 / 오류) 메시지를 표시하여 SQL 인스턴스에서 대용량 데이터를 복사하고 캐스팅했습니다. 약 70000 건의 진행과 메시지 호출 후 양식이 작동을 멈추고 새 메시지를 표시했습니다. 단일 글로벌 인스턴스 대리자를 사용하기 시작했을 때 이런 일이 발생하지 않았습니다.
delegate void ShowMessageCallback(string message);
private void Form1_Load(object sender, EventArgs e)
{
ShowMessageCallback showMessageDelegate = new ShowMessageCallback(ShowMessage);
}
private void ShowMessage(string message)
{
if (this.InvokeRequired)
this.Invoke(showMessageDelegate, message);
else
labelMessage.Text = message;
}
void Message_OnMessage(object sender, Utilities.Message.MessageEventArgs e)
{
ShowMessage(e.Message);
}
답변
용법:
control.InvokeIfRequired(c => c.Visible = false);
return control.InvokeIfRequired(c => {
c.Visible = value
return c.Visible;
});
암호:
using System;
using System.ComponentModel;
namespace Extensions
{
public static class SynchronizeInvokeExtensions
{
public static void InvokeIfRequired<T>(this T obj, Action<T> action)
where T : ISynchronizeInvoke
{
if (obj.InvokeRequired)
{
obj.Invoke(action, new object[] { obj });
}
else
{
action(obj);
}
}
public static TOut InvokeIfRequired<TIn, TOut>(this TIn obj, Func<TIn, TOut> func)
where TIn : ISynchronizeInvoke
{
return obj.InvokeRequired
? (TOut)obj.Invoke(func, new object[] { obj })
: func(obj);
}
}
}
