У меня есть компонент ActiveX, который сканирует фотографию, сохраняет файл во временный файл на жестком диске клиента и загружает фотографию.
У меня есть экземпляр "TwainMan", который выполняет сканирование и который после завершения сканирования вызывает событие "ImageScanned". Это мой основной поток кода:
scanner = new TwainMan();
scanner.ImageScanned += new ImageScannedEventHandler(Scanner_ImageScanned);
Код, который делает это, помещается в метод делегата EventHandler "Scanner_ImageScanned":
private void Scanner_ImageScanned(object Sender, ImageScannedEventArgs e)
{
this.tempFileName = scanner.ToTempFile(e.Image);
MessageBox.Show("Scanned picture stored on the following location:\n" + this.tempFileName);
Upload(this.tempFileName); // works just fine
TriggerJSCallback(); // here is where the problem appears!
}
В методе TriggerJSCallback я запускаю только свой JS Callback:
private void TriggerJSCallback()
{
EventHandler DataPreparingFinished = this.DataPreparingFinished;
if (null != DataPreparingFinished) { DataPreparingFinished(this.tempFileName); }
}
Обратите внимание, что если я запускаю JSCallback "DataPreparingFinished" из основного потока, прослушиватель обратного вызова JS (определенный на моей html-странице) работает просто отлично, но проблема возникает, если триггер "DataPreparingFinished" запускается изнутри " Scanner_ImageScanned "делегат, таким образом, не из основного потока кода.
Что я делаю не так? Кто-нибудь может помочь?
Вот определение обратного вызова JS на html-странице внутри тега.
<script for="AXTwain" event="DataPreparingFinished(args)" language="javascript" type="text/javascript">
function AXTwain::DataPreparingFinished(args) {
alert("JS ALERT: SUCCESS!!! JS Callback working properly." + args);
// alert("The temp file is stored on: " + AXTwain.TempFileName);
}
</script>
Может быть, было бы хорошо, если бы я показывал больше кода, чтобы вы лучше поняли, в чем заключается моя проблема.
Пойдем сверху ...
Ниже приведена моя HTML-страница, которая включает в себя мой экземпляр ActiveXObject и функцию обратного вызова / прослушивания JS.
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ActiveX TWAIN test page</title>
<object id="AXTwain" name="AXTwain" classid="clsid:d8ea830e-38b0-4f3b-8be4-39c417c27583"></object>
</head>
<body onload="myload();">
<h1 style="color:green;">AXTwain test page</h1>
<script type ="text/javascript">
function myload() {
if (AXTwain != null) {
AXTwain.AcquireImage();
}
}
</script>
<script for="AXTwain" event="DataPreparingFinished(args)" language="javascript" type="text/javascript">
// The "for" attribute should be set to the name of instance of your COM component.
// The "event" attribute should be set to the JavaScript function signature for the event.
// The name of the JavaScript function is the instance name of your COM component, followed
// by double colons, followed by the JavaScript signature of the event.
function AXTwain::DataPreparingFinished(args) {
alert("JS ALERT: SUCCESS!!! JS Callback working properly." + args);
}
</script>
</body>
</html>
Ниже мой класс обертки ActiveX ...
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace AXImageAcquisition
{
#region ActiveX attributes
[ProgId("AXImageAcquisition.AXTwain_01")]
[Guid("d8ea830e-38b0-4f3b-8be4-39c417c27583")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IComEvents))]
#endregion
public class AXTwain
{
#region Class Properties and Settings
private TwainMan scanner;
private String tempFileName;
public String TempFileName
{
get { return this.tempFileName; }
}
[ComVisible(false)]
public delegate void EventHandler(string args);
public event EventHandler DataPreparingFinished;
public bool imageScanned = false;
#endregion
#region Class Constructors
public AXTwain()
{}
#endregion
#region Class Methods
[ComVisible(true)]
public void AcquireImage()
{
this.DataPreparingFinished += new EventHandler(Delegate_DataPreparingFinished);
this.scanner = new TwainMan();
this.scanner.ImageScanned += new ImageScannedEventHandler(Scanner_ImageScanned);
TriggerJSCallback(); // HERE IN THE MAIN CODE FLOW THE MESSAGE GETS TO JS!!!
}
/// <summary>
/// Delegate that defines functionality for the ImageScanned event, defined in TwainMan class.
/// </summary>
/// <param name="Sender"></param>
/// <param name="e"></param>
public void Scanner_ImageScanned(object Sender, ImageScannedEventArgs e)
{
this.tempFileName = scanner.ToTempFile(e.Image);
Upload(this.tempFileName);
TriggerJSCallback(); // HERE (NOT IN THE MAIN CODE FLOW) THE MESSAGE NEVER GETS TO JS!!! WHYYYY? :(
}
/// <summary>
/// TODO!!!
/// </summary>
/// <param name="tempFileName"></param>
private void Upload(string tempFileName)
{
// TODO
}
/// <summary>
/// Test method for the DataPreparingFinished trigger.
/// </summary>
public void TriggerJSCallback()
{
EventHandler DataPreparingFinished = this.DataPreparingFinished;
if (null != DataPreparingFinished) DataPreparingFinished(this.tempFileName);
}
/// <summary>
/// Delegate that defines functionality for the DataPreparingFinished event, which is defined in IComEvents.
/// </summary>
/// <param name="msg">Arguments passing from C# to JS.</param>
void Delegate_DataPreparingFinished(string msg)
{
// MessageBox.Show("Delegate_DataPreparingFinished message! (C# code).\n Input message: " + msg);
}
#endregion
}
}
В случае, если вам нужно больше кода, я также могу скопировать / вставить остальную часть кода, то есть класс TwainMan и его зависимости. Однако все, что взято из учебника codeproject, здесь . Кстати, спасибо автору.