|
I have an automation program in C# (latest version with .Net 2.0) that takes control of an instance of IE 6.0 using ShDocVw.dll reference. The other reference is the .NET Microsoft.mshtml.dll. When you navigate to a page with frames, only the top frame is available to use as a document object. I want to programmatically click on a link that is in a frame. I have tried everything to get a reference to the frame and I am getting casting errors in VS. For instance:
InternetExplorer ie = new InternetExplorerClass();
ie.Visible = true;
string url = "http://www.iopus.com/iim/demo/v4/frames/";
Object o = null;
ie.Navigate(url, ref o, ref o, ref o, ref o);
//put a stop here to give time to load all the frames
mshtml.HTMLDocument doc = (mshtml.HTMLDocument)ie.Document;
IHTMLElementCollection fcollection = (IHTMLElementCollection)doc.getElementsByTagName("FRAME");
IEnumerator fEnum = fcollection.GetEnumerator();
fEnum.Reset();
fEnum.MoveNext();
foreach (HTMLFrameElement fElement in fcollection)
{
Console.WriteLine(fElement.tagName + fElement.name);
if (fElement.name == "bottom")
{
object frmNo = 8;
// here it is...
mshtml.IHTMLWindow2 frame = (mshtml.IHTMLWindow2)doc.frames.item(ref frmNo);
}
}
The cast for IHTMLWindow2 does not work. I have tried casting to other things like HTMLDocument, etc and nothing will cast.
The only thing I have found so far that works is to take the src url of the frame and navigate directly to it, then I have the document object available to work with. This method seems wrong. I should be able to enumerate the frames collection and then work with each frame individually.
Has anyone had any luck doing this correctly?
David Bicknell
|
|
|
|
|
Hello,
I am having a problem with set AllowDrop from a callback function for
any types of control boxes, ie. ListView. The following is the example
code that creates the problem. The listView1.AllowDrop never get set
and there is no error or warning as well. Also, if there is any code
after the line "listView1.AllowDrop = false;" will never get excuted.
It seems only happen to the AllowDrop property, others, such as color,
Enabled, are fine.
There is no problem to set AllowDrop from the main thread. For example,
it can be set successfully from the button2 (see below).
I am using .NET 1.1 on Windows XP(SP2).
I appreciate if anybody can help me out here.
Thanks.
John
-------------------------------------------------------------------------------------------
public delegate void ipcEventCallback();
public static ipcEventCallback ipcEventHandler;
private void Form1_Load(object sender, System.EventArgs e)
{
// Init ipcEventCallback interface
ipcEventHandler = new ipcEventCallback(IpcEventHandler);
}
void IpcEventHandler()
{
listView1.AllowDrop = false;
}
private void button1_Click(object sender, System.EventArgs e)
{
ipcEventHandler.BeginInvoke(null, null);
}
private void button2_Click(object sender, System.EventArgs e)
{
listView1.AllowDrop = false;
}
-------------------------------------------------------------------------------------------
|
|
|
|
|
button1_Click(object sender, System.EventArgs e)
{
ipcEventHandler.BeginInvoke(null, null);
}
This invokes the delegate on a different thread. When the delegate is invoked and it attempts to change the ListView's AllowDrop property, it is doing so from a different thread than the one the ListView is running on. That's a no-no. You're only suppose to modify controls on the thread in which they are running.
Is there a reason to use a callback here? Why not do it the way you have in the button2_Click event handler?
|
|
|
|
|
Thanks for reply.
I understand it's from another thread, but only this AllowDrop cannot be modified. Other properties can be changed without any problem. Do you know why is that? I think it may be a problem for .NET.
My application is a process with two threads, GUI and a background running thread. The backgroud thread running as a client communicates with a server and sometimes it needs to update the GUI. The GUI provides a set of callback interface for background thread to use to update the GUI. One of the callback function wants to change a controller's AllowDrop field. From the articles I read, it's the right way to modify GUI through callback thread... I cannot think any other better way since I don't want to block the GUI in anyway.
Thanks,
John
|
|
|
|
|
xjsun wrote: I understand it's from another thread, but only this AllowDrop cannot be modified. Other properties can be changed without any problem. Do you know why is that?
Not a clue. That is strange. Which version of Visual Studio are you using?
xjsun wrote: From the articles I read, it's the right way to modify GUI through callback thread...
Hmm, interesting! I would have thought that since the callback is running on a different thread, via the delegate's BeginInvoke method, that it would be prohibited from modifying the GUI, but there must be some things here I'm not aware of.
xjsun wrote: I cannot think any other better way since I don't want to block the GUI in anyway.
I can understand that. And it rules out suggestiong that you use the Form's BeginInvoke method because it would marshal the delegate invocation to the GUI's thread.
Sorry I can't be of more help.
|
|
|
|
|
xjsun wrote: From the articles I read, it's the right way to modify GUI through callback thread
No, this[^] clearly says that
There are four methods on a control that are safe to call from any thread: Invoke, BeginInvoke, EndInvoke, and CreateGraphics. For all other method calls, you should use one of the invoke methods to marshal the call to the control's thread.
I have a strong suspicion that that is what is causing the problem.
Regards
Senthil
_____________________________
My Blog | My Articles | WinMacro
|
|
|
|
|
Thanks Senthil,
I am sorry that I don't really get what you mean here. Would you please be more specific about it? Thanks.
By the way, I want to clarify little bit here. The test program I posted initially is not exactly what I am using in the application, but it does generate the same problem. In the application, I call the delegate from another thread (not from a button). From the thread, I want to update certain GUI things and this is waht I found how to do it. Are you saying this is not right way of doing it?
Thanks again for the help.
John
|
|
|
|
|
Whenever you need to update a control or form from another thread, you have to use the control's or form's Invoke or BeginInvoke methods. Say you have an event handler in your form that gets notified from another thread. To make it thread safe, it might look something like this:
private void SomeEventHandler(object sender, EventArgs e)
{
if(InvokeRequired)
{
EventHandler handler = new EventHandler(UpdateControl);
Invoke(handler, new object[] { e });
}
else
{
UpdateControl(sender, e);
}
}
private void UpdateControl(object sender, EventArgs e)
{
someLabel.Text = "Some event occurred.";
}
Applying this to your callback, you would check the InvokeRequired property in the callback, and if it is true, you would use the form's Invoke or BeginInvoke to invoke a delegate on the same thread as the GUI in order to modify the form's control. I really don't know of any other way of doing this. That's why your comment about reading some articles that showed a different way threw me off.
I don't think you have to worry about blocking the GUI very much here. True the callback will eventually get handled on the same thread as the GUI, but for simply setting a control property, it shouldn't take any noticable time at all. Hope this helps.
|
|
|
|
|
I think this is what I am missing. I knew I have to use delegate to callback from a thread to the GUI thread but I certainly missed this part. Thank you all for the greate help!
John
|
|
|
|
|
Consider the following code:
public class A
{
private int x = 0;
public int X
{
get
{
return x;
}
set
{
x = value;
}
}
public override string ToString()
{
return x.ToString();
}
}
public class B
{
private ArrayList list = new ArrayList();
private void addItem( A c )
{
list.Add(c);
}
private void changeItem ( ArrayList l )
{
((A)l[0]).X = 5;
}
public void test()
{
addItem( new A());
Console.WriteLine(list[0]);
changeItem(list);
Console.WriteLine(list[0]);
}
public static void Main( string[] args )
{
B b = new B();
b.test();
}
}
The output is:
0
5 Why the output not like:
0
0 changeItem method does not take the reference of the ArrayList, but the value of the object in the collection has changed What is the problem ?
|
|
|
|
|
Kamrul Hasan wrote: changeItem method does not take the reference of the ArrayList, but the value of the object in the collection has changed What is the problem ?
Actually, changeItem() is taking the reference to your ArrayList member variable. Look again in your test() code. You're passing a reference to ArrayList member variable "list" into changeItem().
<br />
public void test()<br />
{<br />
addItem( new A());<br />
Console.WriteLine(list[0]);<br />
changeItem(list);
Console.WriteLine(list[0]);<br />
}<br />
|
|
|
|
|
Thanks for your reply.
In which cases 'ref' keyword should be used? I am confused
As your answer the following two methods will do the same thing isn't it?
1.changeItem( ref ArrayList l )
or
2.changeItem( ArrayList l )
|
|
|
|
|
Member variable "list" is a reference to the ArrayList object and not the object itself. The important thing you need to learn here is the difference between "reference types" and "value types".
All classes such as ArrayList are reference types. Class objects are created via "new" and they only exist in the heap (not the stack). "new" merely returns a reference to that new object. So, when you pass an object reference to a function, you are merely passing a copy of that reference and not a copy of that object.
All structures such as int, long, and float are value types. These types are created on the stack and are not referenced. And yes, they really are structures. int maps to the System.Int32 structure. float maps to the System.Single structure.
So, when you pass a value type into a function, you are passing a copy of its data.
I'm not sure what your goal is here, but if you want to pass a copy of your ArrayList object into your changeItem() function, then you're going to need to clone it. Cloning an object will create a new object having the same object data.
changeItem((ArrayList)list.Clone());
I hope this helps!
|
|
|
|
|
Just in case the OP misses it, only the ArrayList is cloned, not the elements in that list.
Regards
Senthil
_____________________________
My Blog | My Articles | WinMacro
|
|
|
|
|
Since the ArrayList contains integers (ie: value types), it should be copied ok.
But good point to bring up. If it stored reference types, then they'll need to be cloned too.
|
|
|
|
|
Is there any way to group several radio buttons without putting them into a GroupBox ?
|
|
|
|
|
You can only have one grouping of RadioButtons per Form, GroupBox, or Panel. If you want to have several groupings that look like they're on the same form, then I suggest you put them inside borderless Panels.
|
|
|
|
|
Set the Groupnames same with the other radiobuttons
<asp:radiobutton id="RadioButton1" style="Z-INDEX: 101; LEFT: 256px; POSITION: absolute; TOP: 184px"
="" runat="server" <b="">GroupName="a">
<asp:radiobutton id="RadioButton2" style="Z-INDEX: 102; LEFT: 256px; POSITION: absolute; TOP: 224px"
="" runat="server" <b="">GroupName="a">
<asp:radiobutton id="RadioButton3" style="Z-INDEX: 103; LEFT: 440px; POSITION: absolute; TOP: 192px"
="" runat="server" <b="">GroupName="b">
<asp:radiobutton id="RadioButton4" style="Z-INDEX: 104; LEFT: 448px; POSITION: absolute; TOP: 232px"
="" runat="server" <b="">GroupName="b">
|
|
|
|
|
Hi,
Anybody have any ideas on how to best emulate a 'ReadOnly' capability for a radio button? Any help greatly appreciated.
|
|
|
|
|
Enabled = false
My: Blog | Photos
"Man who stand on hill with mouth open will wait long time for roast duck to drop in." -- Confucious
|
|
|
|
|
I'm doing that already. Looks like sh*t.
|
|
|
|
|
Your problem statement is not clear. Can you explain it a bit more ?
|
|
|
|
|
Hi,
Thanks for your interest. I have a data application in which some boolean choices as represented by radio button pairs and at certain points in the application I am representing the data to the user in ReadOnly TextBoxes where applicable. I would like to emulate this functionality in a representation of the RadioButton and am looking for a path of least resistance to accomplish this task. Any help would be greatly appreciated.
|
|
|
|
|
Change the font color back to black after disabling the button?
|
|
|
|
|
I've taken a different approach by building my own custom control that inherits from System.Windows.Forms.RadioButton NameSpace. I'm using GDI+ to alter the presentation of the interface based off a boolean public property I've exposed called 'ReadOnly'. I'm still trying to workout how to cancel 'Click' the click event. Any help would be greatly appreciated.
|
|
|
|