我正在研究一个数据绑定很大的Win.Forms应用程序,我发现了一些奇怪的行为.该应用程序具有单独的I/O线程,通过异步Web请求接收更新,然后将其发送到主/ GUI线程以处理和更新应用程序范围的数据存储(这些数据存储又可能与各种GUI元素绑定数据)等).Web请求另一端的服务器需要定期请求或会话超时.
我已经经历了几个处理线程问题等的尝试解决方案,并且我观察到以下行为:
如果我使用Control.Invoke将更新从I/O线程发送到主线程,并且此更新导致显示MessageBox,则主窗体的消息泵将停止,直到用户单击ok按钮.这也会阻止I/O线程继续最终导致服务器超时.
如果我使用Control.BeginInvoke从I/O线程(或多个)发送更新主线程的主窗体的消息泵并没有停止,但如果一个更新的处理导致了一个消息被显示,其余的处理在用户单击"确定"之前,该更新将暂停.由于I/O线程继续运行并且消息泵继续处理消息,因此可以在具有消息框的那个之前调用几个BeginInvoke用于更新.这导致无序更新,这是不可接受的.
I/O线程向阻塞队列添加更新(非常类似于在.NET中创建阻塞队列<T>).GUI线程使用Forms.Timer定期应用阻塞队列中的所有更新.此解决方案解决了阻塞I/O线程和更新顺序的问题,即下一次更新将永远不会开始,直到上一次完成.但是,性能成本较低,并且在显示更新方面存在延迟,从长远来看这是不可接受的.我希望主线程中的更新处理是事件驱动而不是轮询.
所以对我的问题.我应该怎么做到:
更新:见下面的解决方案
如果我想从另一个线程处理控件,那么对于控件和父窗体的check InvokeRequired和call Invoke方法有什么区别?
if (theForm.InvokeRequired)
Invoke(...)
Run Code Online (Sandbox Code Playgroud)
要么
if (myControl.InvokeRequired)
myControl.Invoke(...)
Run Code Online (Sandbox Code Playgroud)
来自MSDN:
Invoke方法搜索控件的父链,直到找到具有窗口句柄的控件或窗体(如果当前控件的基础窗口句柄尚不存在).
那里.我正在使用C#.wpf,我从C#source获得了一些代码,但我无法使用它.有什么我必须改变的吗?或者呢?
// Delegates to enable async calls for setting controls properties
private delegate void SetTextCallback(System.Windows.Controls.TextBox control, string text);
// Thread safe updating of control's text property
private void SetText(System.Windows.Controls.TextBox control, string text)
{
if (control.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
Invoke(d, new object[] { control, text });
}
else
{
control.Text = text;
}
}
Run Code Online (Sandbox Code Playgroud)
如上面的代码,错误在InvokeRequired和Invoke
目的是,我有一个内容的文本框,将为每个进程递增.
这是文本框的代码. SetText(currentIterationBox.Text = iteration.ToString());
代码有什么问题吗?
感谢您的任何帮助
编辑
// Delegates to enable async calls for setting controls properties
private delegate …Run Code Online (Sandbox Code Playgroud) 我有一个类有以下方法: -
public void setCurrencyCode(List<String> newCurrencycode){
this.currencycode = newCurrencycode;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用Java Relections来调用此方法,如下所示: -
try {
List<String> value = new ArrayList<String>();
value.add("GB");
Class<?> clazz = Class.forName( "com.xxx.Currency" );
Object obj = clazz.newInstance();
Class param[] = { List.class };
Method method = obj.getClass().getDeclaredMethod( "setCurrencyCode", param );
method.invoke( value );
} catch(Exception e) {
System.out.println( "Exception : " + e.getMessage() );
}
Run Code Online (Sandbox Code Playgroud)
但是,在"invoke"调用上引发异常: - java.lang.IllegalArgumentException:object不是声明类的实例
有任何想法吗?
谢谢
莎拉
我正在尝试这样做:
<script>
var MyItem;
MyItem = new myobj('testobj');
function myobj(id)
{
var _id = id;
this.toggle = function()
{
...
}
function draw()
{
document.body.innerHTML += "<a onclick='" + MyItem + ".toggle();'>link</a>";
}
draw();
}
</script>
Run Code Online (Sandbox Code Playgroud)
我得到"函数未定义",但可以成功从控制台调用MyItem.toggle().我也尝试过:
document.body.innerHTML += "<a onclick='(function(){" + MyItem + ".toggle();})()'>link</a>";
Run Code Online (Sandbox Code Playgroud)
必须在javascript中动态创建锚点.如何从动态创建的锚中调用MyItem对象方法toggle()?
ps,我正在从内存中输入js,所以如果有语法错误我道歉.
如果从多个后台线程访问,是否需要同步对Dispatcher.Invoke的调用?
我知道Dispatcher.BeginInvoke会自动同步对silverlight app的调用(http://msdn.microsoft.com/en-us/library/z8chs7ft(v=vs.95).aspx)
对于wpf应用程序也是如此,或者我应该取消注释下面的lock语句.
public MainWindow()
{
InitializeComponent();
Dispatcher.BeginInvoke(new Action(() =>
{
const int MAX_NR_THREADS = 1000;
for (int i = 0; i < MAX_NR_THREADS; ++i)
{
int j = i+1;
new Thread(()=>ThreadMethod(j)).Start();
}
}));
}
private void ThreadMethod(int threadId)
{
const int ONE_MILLION = 1000000;
for (int i = 0; i < ONE_MILLION/threadId; ++i)
{
//lock(lockObj)
//{
this.Dispatcher.Invoke(new Action(() =>
{
int sum = 0;
for (int j = 0; j < ONE_MILLION/10000; ++j)
{
sum += …Run Code Online (Sandbox Code Playgroud) 例外是代码:
private void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
{
ActiveDownloadJob adJob = e.UserState as ActiveDownloadJob;
if (adJob != null && adJob.ProgressBar != null)
{
adJob.ProgressBar.Invoke((Action)(() => adJob.ProgressBar.Value = e.ProgressPercentage));
}
}
Run Code Online (Sandbox Code Playgroud)
在线上:
adJob.ProgressBar.Invoke((Action)(() => adJob.ProgressBar.Value = e.ProgressPercentage));
Run Code Online (Sandbox Code Playgroud)
这是form1中的ActiveDownloadJob类:
class ActiveDownloadJob
{
public DownloadImages.DownloadData DownloadData;
public ProgressBar ProgressBar;
public WebClient WebClient;
public ActiveDownloadJob(DownloadImages.DownloadData downloadData, ProgressBar progressBar, WebClient webClient)
{
try
{
this.DownloadData = downloadData;
this.ProgressBar = progressBar;
this.WebClient = webClient;
}
catch (Exception err)
{
MessageBox.Show(err.ToString());
}
}
}
Run Code Online (Sandbox Code Playgroud)
我不确定我是否需要调用此行,因为我现在不使用背景工作者,但我不确定.
这是完整的异常消息:在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke
System.InvalidOperationException …Run Code Online (Sandbox Code Playgroud) 我正在开发的一个c#应用程序主要包括对来自摄像头的图像执行操作并将其打印在图片框上.它有一个用c ++编写的库,它从网络摄像头(imgcam)中检索图像,然后复制它们(imgcam_copy),然后将它们传送给请求它们的托管代码.反过来,应用程序的托管部分由一个辅助线程组成,该辅助线程执行一个while循环,该循环从非托管库中获取图像并将它们打印到图片框.
一切正常,一切都是最精致的部分,即从非托管代码到托管代码的动态资源管理对我来说似乎很清楚,我知道我正在做什么(至少我希望如此),但问题在于编写使线程正常工作所需的代码.事实上,即使在浏览网页数小时之后,我仍有很多事情不清楚.
我不得不用UI线程打印图像,所以我必须依赖Invoke.
delegate void setImageCallback(Image img);
private void showFrame(Image img)
{
if (pboxCam.InvokeRequired)
{
this.Invoke(new setImageCallback(showFrame), img);
}
else
{
pboxCam.Image = img;
}
}
Run Code Online (Sandbox Code Playgroud)
我有很多问题:
1)调用昂贵的操作?我已经做了很多努力来减少主要操作在图像上的执行时间,在显示结果时浪费部分收益会令人失望.
2)您是否认为同步使用Invoke或异步BeginInvoke +图像副本更好?
3)将Image作为函数参数但是作为类的成员访问它是否有帮助?
private delegate void setImageCallback();
private void showFrame()
{
if (pboxCam.InvokeRequired)
{
this.Invoke(new setImageCallback(showFrame));
}
else
{
pboxCam.Image = cm.bitmap;
}
}
Run Code Online (Sandbox Code Playgroud)
4)也许你不会分享我对性能的担心,但我想知道你是否分享了线程安全性.UI线程只是想在非UI线程复制它时显示图像,依赖异步机制真的不安全吗?
众所周知,您无法使用除GUI线程之外的任何其他线程更改GUI.所以常用的一个简单技巧(我使用的)是调用:
this.Invoke((MethodInvoker)delegate { pictureBox1.Visible = false; });
Run Code Online (Sandbox Code Playgroud)
我正在构建我的程序并启动它,很快就注意到我忘了把它PictureBox.Load(string url)放入调用程序中,但是没有发生错误.
所以我很好奇,为什么我不允许这样做(在非GUI线程中):
pictureBox1.Visible = false; // eg.
Run Code Online (Sandbox Code Playgroud)
但我被允许这样做:
pictureBox1.Load(url); // url = link to image
Run Code Online (Sandbox Code Playgroud) 有人可以解释下面的代码:
this.Invoke((MethodInvoker)delegate
{
lblNCK.Text = cncType;
});
Run Code Online (Sandbox Code Playgroud)
这是它来自哪里:
string cncType;
if (objDMainCncData != null)
{
int rc = objDMainCncData.Init(objDGroupManager.Handle);
if (rc == 0)
{
cncType = objDMainCncData.GetCncIdentifier();
if (cncType != string.Empty)
{
if (cncType.ToUpper().IndexOf("+") != -1)
_bFXplus = true;
this.Invoke((MethodInvoker)delegate
{
lblNCK.Text = cncType;
});
}
}
else
{
DisplayMessage("objDMainCncData.Init() failed ! error : " + rc.ToString());
}
}
}
Run Code Online (Sandbox Code Playgroud)
我没有使用"this.Invoke((MethodInvoker)委托").
提前谢谢你.
彼得.
invoke ×10
c# ×6
winforms ×3
begininvoke ×2
wpf ×2
.net ×1
controls ×1
delegates ×1
dispatcher ×1
dynamic ×1
java ×1
javascript ×1
messagebox ×1
object ×1
onclick ×1
reflection ×1
synchronize ×1