菜鸟想写一个可以对CTAIS自动填表的软件,主要是WinForm+Webbrowser,目前已经解决了文本框和下拉框的自动填表,但碰到这个表格不知道该如何下手了,请教各位大虾,多谢!
写成这样不知道如何继续……
//填充表格
mshtml.IHTMLElementCollection FixRC;
FixRC = (mshtml.IHTMLElementCollection)doc.all.tags("datawindow");
mshtml.IHTMLElement FixRChwmc = (mshtml.IHTMLElement)FixRC.item("dw_dk_zb", 0);//货物名称
//后面写不下去了……
这是HTML源文件,如果需要xdatawindow.htc文件我可以上传:
<TABLE style="WIDTH: 100%; HEIGHT: 30%" border=0>
<TBODY><TR><TD style="WIDTH: 100%; HEIGHT: 100%">
<ctais:datawindow id=dw_dk_zb style="WIDTH: 100%; HEIGHT: 100%" node="DSO_FP/FP_DK_FP_ZB" autoAddRow="true">
<COLUMN id=HWMC fill="yes" colwidth="6" caption="货物名称" type="INPUT" />
<COLUMN id=GGXH colwidth="2" caption="规格型号" type="INPUT" />
<COLUMN id=JLDW colwidth="2" caption="计量单位" type="INPUT" />
<COLUMN id=HWSL fill="yes" onchange="HWSL_onchange(this)" colwidth="3" caption="货物数量" type="INPUT" preset="number(10,8)" />
<COLUMN id=DJ fill="yes" onchange="DJ_onchange(this)" colwidth="3" caption="含税单价" type="INPUT" preset="number(10,8)" />
<COLUMN id=JE onchange="JE_onchange(this)" colwidth="3" caption="含税金额" type="INPUT" preset="number(14,2)" total="yes" />
<COLUMN id=SL fill="yes" view="SL_MC" key="SL_DM" node="DSO_SL" onchange="SL_onchange(this)" colwidth="2" caption="税率" type="SELECT" />
<COLUMN id=SE colwidth="3" caption="税额" type="INPUT" preset="number(14,2)" total="yes" /></ctais:datawindow>
</TD></TR></TBODY></TABLE>
系统界面如下:
写成这样不知道如何继续……
//填充表格
mshtml.IHTMLElementCollection FixRC;
FixRC = (mshtml.IHTMLElementCollection)doc.all.tags("datawindow");
mshtml.IHTMLElement FixRChwmc = (mshtml.IHTMLElement)FixRC.item("dw_dk_zb", 0);//货物名称
//后面写不下去了……
这是HTML源文件,如果需要xdatawindow.htc文件我可以上传:
<TABLE style="WIDTH: 100%; HEIGHT: 30%" border=0>
<TBODY><TR><TD style="WIDTH: 100%; HEIGHT: 100%">
<ctais:datawindow id=dw_dk_zb style="WIDTH: 100%; HEIGHT: 100%" node="DSO_FP/FP_DK_FP_ZB" autoAddRow="true">
<COLUMN id=HWMC fill="yes" colwidth="6" caption="货物名称" type="INPUT" />
<COLUMN id=GGXH colwidth="2" caption="规格型号" type="INPUT" />
<COLUMN id=JLDW colwidth="2" caption="计量单位" type="INPUT" />
<COLUMN id=HWSL fill="yes" onchange="HWSL_onchange(this)" colwidth="3" caption="货物数量" type="INPUT" preset="number(10,8)" />
<COLUMN id=DJ fill="yes" onchange="DJ_onchange(this)" colwidth="3" caption="含税单价" type="INPUT" preset="number(10,8)" />
<COLUMN id=JE onchange="JE_onchange(this)" colwidth="3" caption="含税金额" type="INPUT" preset="number(14,2)" total="yes" />
<COLUMN id=SL fill="yes" view="SL_MC" key="SL_DM" node="DSO_SL" onchange="SL_onchange(this)" colwidth="2" caption="税率" type="SELECT" />
<COLUMN id=SE colwidth="3" caption="税额" type="INPUT" preset="number(14,2)" total="yes" /></ctais:datawindow>
</TD></TR></TBODY></TABLE>
系统界面如下:
解决方案 »
- MongoDB 无法查找附近POI
- c#怎么多开,比如一个聊天客户端,我想同时打开多个怎么办?
- 我的vs2010怎么不识别directx sdk?
- 关于鼠标跟随屏幕上的光点移动的问题
- 关于在backgroundworker中操作UI控件
- 怎么取得 Repeater控件<ItemTemplate>里面的控件
- 在线求救!!在C#中如何获得一个图片上面的三分之一!
- C#高手请进________开发打印控件
- C#。net在母版中用link的shortcut icon和Bookmark做IE地址栏图标和收藏栏图标没有用是什么原因啊?
- C#如何制作DLL
- C#传结构体给C++,类型转换,封送结构体,动态申请数组空间
- 关于子窗体调用父窗体函数问题
如果可能的话,不要用htc,改成其它js框架
点左上角的箭头(单击选择元素),在页面上的货物名称中点一下,再把看到的dom结构贴出来。
请问是不是该表格是用JS动态创建就无法看得到?
另外,我查看了下挂下该页面下的index.js,发现了这些相关的代码:
1.
xmlNodeCopy(frm_fpxx.DSO_FP,DSO_PTTD,"FP_DK_FP_ZB");
2.这貌似是删除空行?
for (var i=0;i<frm_fpxx.dw_dk_zb.rowCount;i++){
if (frm_fpxx.dw_dk_zb.cell(i,0).value==null || frm_fpxx.dw_dk_zb.cell(i,0).value==""){
frm_fpxx.dw_dk_zb.deleteRow(i);
}
}
3.注释导出是乱码,抱歉……
function dso_bj(){
if (frm_fpxx.dw_dk_zb.modified)
{return false;
}
for (var i=0;i<23 ;i++ )
{
//DWԪУ
var fp_dso=frm_fpxx.DSO_FP.childNodes(0).childNodes(i).text;
var copy_dso=frm_fpxx.DSO_COPY.childNodes(0).childNodes(i).text;
if (fp_dso!=copy_dso)
{return false;
}
}
return true;
4.此处应该为税额和总计,分别在表格的第8列和第6列,结果保留两位小数
var nSe=frm_fpxx.dw_dk_zb.col(7).total;
DSO_PTTD.selectSingleNode("ROOT/DYNR/SEHJ").text=convertCN(round(nSe,2)); var iNum=frm_fpxx.dw_dk_zb.rowCount;
var sum=frm_fpxx.dw_dk_zb.col(5).total;
DSO_PTTD.selectSingleNode("ROOT/DYNR/HJ_XX").text= round(sum,2);
var dd=round(sum,2);
DSO_PTTD.selectSingleNode("ROOT/DYNR/HJ_DX").text=convertCN(dd);
5.此处貌似是金额合计,有如下代码:(请问如何设置"frm_fpxx.dw_dk_zb.cell(i,5).value"?)
var oDoc=loadXml(arg);
je =round(oDoc.documentElement.selectSingleNode("JEHJ").text,2);
var iNum=frm_fpxx.dw_dk_zb.rowCount;
for (var i=0; i < iNum; i++)
{
jehj += round(frm_fpxx.dw_dk_zb.cell(i,5).value,2);
}
因为是单位的内网,所以页面暂时没办法贴出来了……
HTC文件在此:http://pan.baidu.com/share/link?shareid=148816522&uk=2785352337
这个htc中的大部分函数,都是对htcDatawindow功能的简单封装,即htc本身没有实际地进行处理,而是调用了htcDatawindow的相应功能。
这就意味着,页面上显示的可能不是html元素,而是由这个ActiveX呈现的UI界面。这样用f12确实就定位不到元素,因为根本就不存在,同时也意味着用定位html元素来填充表格的做法是行不通的。
好消息是,这个htc封装和公开了比较完整的htcDataWindow的功能,所以你可以直接操作这个datawindow对象来对表格进行处理。
比如htc公开了setCellValue方法:
function setCellValue(rowIndex,colIndex,value,bRaiseEvent,bRecordChangeModified)
你可以试试在页面上写一个js:
document.getElementById('dw_dk_zb').setCellValue(0,0,'test');
看看能不能把“test”填到表格中。
htc中还有其它方法,也可以通过试验来确定它的功能,大部分方法看名字也能大概猜到它的功能。比如:
addRow应该是添加一行,htcDatawindow.cmdSave应该对应保存的功能。
这里是kb912945.js文件,貌似直接有载入xdatawindow.htc的方法?
http://pan.baidu.com/share/link?shareid=3776759826&uk=2785352337
请问是否有办法直接调用xdatawindow.htc中的setCellValue函数?
如果要在Webbrowser中添加JS,使用这样的语句是否可行?
IHTMLDocument2.createElement("<script>……</script>");
再写什么JS貌似又是一个对我这菜鸟来说有难度的问题了……
你能直接在html页面上加js吗?
PS:目前还不会怎样在html页面上加js……
//需要调用的Frame
IHTMLWindow2 win1 = (IHTMLWindow2)webBrowser2.Document.Window.Frames[1].Frames[0].DomWindow;
//获得Iframe doc
IHTMLDocument2 doc = CodecentrixSample.CrossFrameIE.GetDocumentFromWindow(win1);
mshtml.IHTMLElementCollection Fix;
Fix = (mshtml.IHTMLElementCollection)doc.all.tags("datawindow");
mshtml.IHTMLElement FixDW = (mshtml.IHTMLElement)Fix.item("dw_dk_zb", 0);
那个是从网上找的类库,是为了解决跨域访问frame的问题,貌似是用IHTMLWindow2取得接口,代码如下:
PS:要搭建测试环境的话,这个我得准备准备……
namespace CodecentrixSample
{
public class CrossFrameIE
{
// Returns null in case of failure.
public static IHTMLDocument2 GetDocumentFromWindow(IHTMLWindow2 htmlWindow)
{
if (htmlWindow == null)
{
return null;
} // First try the usual way to get the document.
try
{
IHTMLDocument2 doc = htmlWindow.document;
return doc;
}
catch (COMException comEx)
{
// I think COMException won't be ever fired but just to be sure ...
if (comEx.ErrorCode != E_ACCESSDENIED)
{
return null;
}
}
catch (System.UnauthorizedAccessException)
{
}
catch
{
// Any other error.
return null;
} // At this point the error was E_ACCESSDENIED because the frame contains a document from another domain.
// IE tries to prevent a cross frame scripting security issue.
try
{
// Convert IHTMLWindow2 to IWebBrowser2 using IServiceProvider.
IServiceProvider sp = (IServiceProvider)htmlWindow; // Use IServiceProvider.QueryService to get IWebBrowser2 object.
Object brws = null;
sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out brws); // Get the document from IWebBrowser2.
SHDocVw.IWebBrowser2 browser = (SHDocVw.IWebBrowser2)(brws); return (IHTMLDocument2)browser.Document;
}
catch
{
} return null;
} private const int E_ACCESSDENIED = unchecked((int)0x80070005L);
private static Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
private static Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E");
} // This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface!
[ComImport(), ComVisible(true), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject);
}
}
没有环境很难猜到问题,理论上你的跨域取document的方法对的,id、包括frame的索引号什么都是对的话,应该能取到dw_dk_zb元素
请教大大,既然“用定位html元素来填充表格的做法是行不通的”,取到dw_dk_zb元素之后下一步该往哪里走呢?
大概就是这样,htc中所有public的method都可以调用
不过大大,貌似IHTMLDocument2没有InvokeScript方法,只能用execScript的样子,譬如这里也有同样的问题:http://social.msdn.microsoft.com/Forums/windows/en-US/64703e92-9195-488f-a6fc-e9c8a6caab5e/calling-javascripts-from-c
请问,改成这样写可以吗?
execScript("setCellValue(0,0,'test')" , "jscript" );
因为你用WebBrowser,按通常做法取到的是System.Windows.Forms.HtmlElement,对它可以用
element.InvokeMember("setCellValue", new object [] {0, 0, "test"})如果你能取到嵌套在iframe里面的document(System.Windows.Forms.HtmlDocument),那么可以用
document.InvokeScript("eval", new object[]{@"
var dataWindow = document.getElementById('dw_dk_zb');
dataWindow.setCellValue(0,0,'test');
"});IHTMLWindow2.execScript应该也可以,但这个IHTMLWindow2应该要是代表iframe的window对象,
脚本中也要先找到htc元素:
execScript(@"document.getElementById('xxx').setCellValue(0,0,'test')" 。。总之如何从c#去执行js并不是难点,困难是如何定位、找到这个htc元素,以及验证用htc提供的public方法去操作DataWindow是否可行。我看你的iframe好像是嵌套了两层的,不知道它们是否都是跨域的?调试的时候不要着急,一步一步来,先找到外层的iframe,看看它是否为null,然后随便在这个iframe里找个元素,用outerHTML看看是否得到它的html代码,这样可以验证第一层跨域读取成功,然后再进第二层这样慢慢调试,仔细找应该可以得到dw_dk_zb这个DataWindow元素的,得到同样用outerHTML看一下验证确实是这个元素无误,再对其调用htc成员方法。
我是这样写的://需要调用的Frame
IHTMLWindow2 win1 = (IHTMLWindow2)webBrowser2.Document.Window.Frames[1].Frames[0].DomWindow;
//获得Iframe doc
IHTMLDocument2 doc = CodecentrixSample.CrossFrameIE.GetDocumentFromWindow(win1);
mshtml.IHTMLElementCollection Fix;
Fix = (mshtml.IHTMLElementCollection)doc.all.tags("datawindow");
mshtml.IHTMLElement FixDW = (mshtml.IHTMLElement)Fix.item("dw_dk_zb", 0);
通过断点可以看见FixDW的innerHTML是:
<column type=INPUT id=HWMC caption="货物名称" fill="yes" colwidth=6 />
<column type=INPUT id=GGXH caption="规格型号" colwidth=2 />
<column type=INPUT id=JLDW caption="计量单位" colwidth=2 />
<column type=INPUT id=HWSL caption="货物数量" colwidth=3 fill="yes" onchange="HWSL_onchange(this)" preset="number(10,8)"/>
<column type=INPUT id=DJ caption="含税单价" colwidth=3 fill="yes" onchange="DJ_onchange(this)" preset="number(10,8)"/>
<column type=INPUT id=JE caption="含税金额" colwidth=3 onchange="JE_onchange(this)" preset="number(14,2)" total="yes" />
<column type=SELECT id=SL caption="税率" colwidth=2 fill="yes" node="DSO_SL" key="SL_DM" view="SL_MC" onchange="SL_onchange(this)"/>
outerHTML是<ctais:datawindow id=dw_dk_zb style=……请问大大,这样是不是就意味着已经取得了dw_dk_zb这个DataWindow元素?
然后我这样写execScript: win1.execScript("FixDW.setCellValue(0,0,'test')", "javascript");然后就运行出错了……
win1.execScript("FixDW.setCellValue(0,0,'test')", "javascript");
这句是错的,FixDW是c#中的变量,js中当然是不认识这个变量的。应该是
doc.parentWindow.execScript(@"document.getElementById('dw_dk_zb').setCellValue(0,0,'test')");
请教大大,像这样“exeScript(@“……”);”用法,和通常的exeScript("…","Script")不同,麻烦大大进一步解说下,多谢!
@这种叫原意字符串,看msdn说明:
http://msdn.microsoft.com/zh-cn/library/vstudio/ms228362.aspx第二参数不写,默认就是javascript
100分双手奉上