VB.NET 2010,.NET 4
你好,
我最近读到了使用SynchronizationContext对象来控制某些代码的执行线程.我一直在使用通用子例程来处理(可能)跨线程调用,例如更新使用的UI控件Invoke.我是一名业余爱好者,很难理解任何特定方法的优缺点.我正在寻找一些有关哪种方法可能更可行以及为什么更有用的见解.
更新:此问题的部分原因在于MSDN页面中Control.InvokeRequired的以下语句.
更好的解决方案是使用
SynchronizationContext返回的SynchronizationContext而不是控件来进行跨线程编组.
而且,对于为什么,在我看来,大多数关于SO上此类问题的问题的答案的建议都提出了Invoke这种方法,并没有提到这种方法.
方法1:
Public Sub InvokeControl(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of T))
If Control.InvokeRequired Then
Control.Invoke(New Action(Of T, Action(Of T))(AddressOf InvokeControl), New Object() {Control, Action})
Else
Action(Control)
End If
End Sub
Run Code Online (Sandbox Code Playgroud)
方法2:
Public Sub UIAction(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of Control))
SyncContext.Send(New Threading.SendOrPostCallback(Sub() Action(Control)), Nothing)
End Sub
Run Code Online (Sandbox Code Playgroud)
在我的UI表单的构造函数中定义SyncContext的Threading.SynchronizationContext …
好吧,假设我有b.exe,它接受一个字符串参数.我想在a.cpp中使用系统调用b.exe:
string s1 = "hallo";
system("b.exe s1");
printf("s1 after invoke = %s",s1);
Run Code Online (Sandbox Code Playgroud)
这是b.cpp中的代码:
int main(string s)
{
s = "hello world";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我想要的是,当我运行a.exe时,输出将是:
s1 after invoke = hello world
Run Code Online (Sandbox Code Playgroud)
有可能这样做吗?基本上,我只是想将一个变量传递给一个exe,但它必须通过引用,而不仅仅是值,因为我希望在我调用的exe中处理和修改该变量.我已经在互联网上搜索了解决方案,但它只提供了一种方法,可以通过值将变量传递给exe,而不是通过引用.
任何建议将非常感激,但如果可能的话,我希望以上述更正代码的形式提出建议,并包括文件,如果有的话.谢谢你的帮助 :)
试图从其他线程更新UI控件.
目前正在使用BeginInvoke,老实说它工作正常,但我一直听说你如何使用SynchronizationContext来做同样的事情.
哪个更受欢迎?
另外,从线程更新UI是不好的做法吗?提出一个事件并让主要表单处理它或者还有其他更好的方法来处理它会更好吗?
对不起,我有些主观的问题,但在线程的世界这么多的选择,我试图抓住他们的分歧,每个人都适用,与写可读和可扩展的代码对未来的最佳实务.
编辑:现在我也看到了TaskScheduler.FromCurrentSynchronizationContext路线也是如此..有很多选择x_x
我正在编写单元测试来测试在 GUI 中键入的数据是否经过验证和正确记录。目前我正在使用这样的代码:
using (MyControl target = new MyControl())
{
PrivateObject accessor = new PrivateObject(target);
TextBox inputTextBox = (TextBox)accessor.GetField("InputTextBox");
string expected, actual;
expected = "Valid input text.";
inputTextBox.Text = expected;
// InputTextBox.TextChanged sets FieldData.Input
actual = target.FieldData.Input;
Assert.AreEqual(expected, actual);
}
Run Code Online (Sandbox Code Playgroud)
但我宁愿使用 Validated 事件而不是 TextChanged 事件。
using (MyControl target = new MyControl())
{
PrivateObject accessor = new PrivateObject(target);
TextBox inputTextBox = (TextBox)accessor.GetField("InputTextBox");
string expected, actual;
bool valid;
expected = "Valid input text.";
inputTextBox.Text = expected;
valid = inputTextBox.Validate();
// InputTextBox.Validating returns …Run Code Online (Sandbox Code Playgroud) 我有两种形式,一种是MainForm第二种形式DebugForm.MainForm有一个按钮,用于设置和显示DebugForm,并将引用传递给已打开的SerialPort:
private DebugForm DebugForm; //Field
private void menuToolsDebugger_Click(object sender, EventArgs e)
{
if (DebugForm != null)
{
DebugForm.BringToFront();
return;
}
DebugForm = new DebugForm(Connection);
DebugForm.Closed += delegate
{
WindowState = FormWindowState.Normal;
DebugForm = null;
};
DebugForm.Show();
}
Run Code Online (Sandbox Code Playgroud)
在DebugForm中,我附加了一个方法来处理DataReceivedserialport连接的事件(在DebugForm的构造函数中):
public DebugForm(SerialPort connection)
{
InitializeComponent();
Connection = connection;
Connection.DataReceived += Connection_DataReceived;
}
Run Code Online (Sandbox Code Playgroud)
然后在该Connection_DataReceived方法中,我更新DebugForm中的TextBox,即使用Invoke进行更新:
private void Connection_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
_buffer = Connection.ReadExisting();
Invoke(new EventHandler(AddReceivedPacketToTextBox));
}
Run Code Online (Sandbox Code Playgroud)
但我有一个问题.当我关闭DebugForm,它抛出一个ObjectDisposedException上Invoke(new EventHandler(AddReceivedPacketToTextBox));线.
我怎样才能解决这个问题?欢迎任何提示/帮助!
UPDATE …
我对 Java (6/7/8) 语法有一个愚蠢的问题 - 这两个方法调用片段总是等效的吗?
和this
this.myMethod(4);
Run Code Online (Sandbox Code Playgroud)没有this
myMethod(4);
Run Code Online (Sandbox Code Playgroud)注意:当然,问题是关于参数的每个数字、类型和组合
较弱的语句:给定程序P,我可以仅通过在每个方法调用前面P'删除来创建程序吗?this.
我考虑了本地类、匿名类、内部类和各种继承,但没有发现任何矛盾。所以我相信这两个片段实际上是相同的。不幸的是我无法找到任何合适的证明(例如来自官方语法)。
你能通过反证证明我错了,或者给我一些构建等价证明的线索吗?多谢。
编辑:等价被证明是错误的(见下面的评论)那较弱的陈述呢?
Winforms、C#、VS2010。
我有一个在我的应用程序的生命周期内运行的轮询线程。
有时它会在我的主窗体上调用一个事件。我已经很多年没有碰过代码了,它运行成功,但现在我需要在参数列表中添加一个“out”参数。我在网上搜索过,但我发现的所有线程都与反射有关,并且尝试转换为我的上下文很复杂。我的不使用反射。
有人可以帮忙解决这个问题吗?在反射线程上,我读到人们似乎检查一些对象数组以获取输出参数结果,我在代码中没有使用它,而且我也不知道从哪里获取它。
private bool OnNeedUpdateCreateEvent(string title, string message,
bool creatingNew, out string newPlanName)
{
newPlanName = "";
// 1st pass through this function.
// Check to see if this is being called from another thread rather
// than the main thread. If so then invoke is required
if (InvokeRequired)
{
// Invoke and recall this method.
return (bool)Invoke(new onNeedToUpdatePlanEvent(OnNeedUpdateCreateEvent),
title, message, creatingNew, out newPlanName); <- wrong out param
}
else
{
// 2nd pass through this function due …Run Code Online (Sandbox Code Playgroud) 我在 C++ 中应用 Invoke 来使用应用程序的对象,但发生错误。错误:信息不可用,没有为 GPNSAutomation.dll 加载符号我的代码是:
::CLSIDFromProgID(OLESTR("SGNSAutomation.SGNSApplication"), &clsid);
IID iid;
HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL,
IID_IDispatch, (LPVOID*)&pWMPDispatch);
IDispatch * pdisp = (IDispatch *)NULL;
DISPID dispid;
DISPPARAMS params= {NULL,NULL,0,0};
params.cArgs =1;
OLECHAR * Name = OLESTR("importCase");
HRESULT hresult =pWMPDispatch->GetIDsOfNames(IID_NULL,
&Name,1,LOCALE_SYSTEM_DEFAULT,&dispid);
hresult =pWMPDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, ¶ms, NULL, NULL,
NULL);
_ASSERT(hr==S_OK);
Run Code Online (Sandbox Code Playgroud) 我有两个WinForms(Setting和frmMain).我在Setting的表单中有一个TreeView,我想以FillTree第二种形式调用它的方法frmMain.
我正在使用它TreeView.Invoke来进行线程化.
这是我在Setting的表单中填充TreeView的代码:
TreeNode parentNode;
public void FillTree(DataTable dtGroups, DataTable dtGroupsChilds)
{
treeViewGroups.Nodes.Clear();
if (dtGroups == null) return;
foreach (DataRow rowGroup in dtGroups.Rows)
{
parentNode = new TreeNode
{
Text = rowGroup["Groupname"].ToString(),
Tag = rowGroup["Groupid"]
};
treeViewGroups.Invoke(new Add(AddParent), new object[] { parentNode });
if (dtGroupsChilds == null) continue;
foreach (DataRow rowUser in dtGroupsChilds.Rows)
{
if (rowGroup["Groupid"] == rowUser["Groupid"])
{
TreeNode childNode = new TreeNode
{
Text = rowUser["Username"].ToString(),
Tag = …Run Code Online (Sandbox Code Playgroud) 我要打印 hi GrandFather
但它似乎打印喜父亲。我不明白如何区分findSpecial和findVirtual
我想要有人可以帮助我。谢谢
class GrandFather{
void thinking(){
System.out.println("hi GrandFather");
}
}
class Father extends GrandFather{
void thinking(){
System.out.println("hi Father");
}
}
class Son extends Father{
void thinking(){
MethodType mt=MethodType.methodType(void.class);
//MethodHandle mh=MethodHandles.lookup().findVirtual(GrandFather.class,"thinking",mt).bindTo(this);
MethodHandle mh;
mh = MethodHandles.lookup().findSpecial(GrandFather.class,"thinking",mt,getClass());
mh.invoke(this);
}
}
public static void main(String[] args){
(new MethodHandleTest().new Son()).thinking();
}
Run Code Online (Sandbox Code Playgroud)
