when assigning an object to the ObjectForScripting property of a WebBrowser control the methods of this object can be called by JavaScript by using windows.external.[method_name]. This works without problems.
But how I need to design this C# object when I have a JavaScript function like this (accessing a sub object): window.external.app.testfunction();
I tested it with following C# object assigned to the ObjectForScripting property:
[ComVisible(true)]
public class TestObject
{
public App app = new App();
}
public class App
{
public void testfunction()
{
}
}
But this unfortunately does not work and leads to a JavaScript error saying "function expected".
Any idea on how the C# object has to look like that this JavaScript command is working?
Thank you for any tips on that
Andreas
I suggest you use InterfaceIsIDispatch-based interfaces to expose the object model from C# to JavaScript:
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApplication
{
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IApp
{
void testFunction();
}
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ITestObject
{
IApp App { get; }
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(ITestObject))]
public class TestObject: ITestObject
{
readonly App _app = new App();
public IApp App
{
get { return _app; }
}
}
[ComVisible(true)]
public class App : IApp
{
public void testFunction()
{
MessageBox.Show("Hello!");
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.webBrowser1.ObjectForScripting = new TestObject();
this.webBrowser1.DocumentCompleted += webBrowser1_DocumentCompleted;
this.webBrowser1.Navigate("about:blank");
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
this.webBrowser1.Navigate("javascript:external.App.testFunction()");
}
}
}
Related
I need to get a non-static field from App.xaml.cs class, but i don't know how.
this is my code from App.xaml.cs containing the IsUserLoggedIn field:
public partial class App : Application
{
internal bool IsUserLoggedIn { get; private set; }
}
and this is the code calling the IsUserLoggedIn field from my EventTable.cs class:
internal class EventTable
{
private void UpdateEvents()
{
if (App.Current.IsUserLoggedIn) // here is an error: "Applcation"
{ // does not contain the definition
// of "IsUserLoggedIn"
}
}
}
App.Current is the same static property as Application.Current and has declared Application type. you need to cast it to App. I suggest to do it this way:
public partial class App : Application
{
internal bool IsUserLoggedIn { get; private set; }
public static App Instance
{
get { return Current as App; }
}
}
then use it in condition:
internal class EventTable
{
private void UpdateEvents()
{
if (App.Instance.IsUserLoggedIn)
{
}
}
}
So I've created a WebDriverActionListener class. I register with my driver instance however the OnElementClicking does not fire.
I'm trying to register with my page constructer like so:
public Page(IWebDriver driver): base(driver)
{
this.driver = new WebDriverActionListener(driver);
PageFactory.InitElements(driver, this);
}
Here is my eventlistner class
public class WebDriverActionListener : EventFiringWebDriver
{
#region Object Declarations
private readonly IWebDriver driver;
#endregion
public WebDriverActionListener(IWebDriver parentDriver) : base(parentDriver)
{
driver = parentDriver;
}
protected override void OnElementClicking(WebElementEventArgs e)
{
base.OnElementClicking(e);
if (IsMobile()) //method in another class
{
e.Element.Move(driver); //method in another class
}
}
}
Could someone suggest why this is, I do not to do register my listener class like so driverExtensions = new WebDriverExtensions(this.driver); as it would require quite a lot of code change.
Thanks
I wanted to use a DLL library code and link / reference it with my c# code. The reference seems to be working, when defining var instance = new ProjectM1() without any problems.
But in the following line appears an error that ProjectM1 does not contain a definition for ProjectM1 and it couldn't find a extension method (Maybe a using directive or assembly reference is missing)
namespace GanttC
{
public class ProjectM1 : ProjectM1<Task, object>
{
}
public class ProjectM1<T, R> : IProjectM1<T, R>
where T : Task
where R : class
{
public ProjectM1() (routine to call !)
{
Now = 0;
Start = DateTime.Now;
TimeScale = GanttC.TimeScale.Day;
}
}
}
Here now the main code to call routine ProjectM1 in public class ProjectM1:
using GanttC
namespace WindowsApp2
{
public partial class Form4 : Form
{
Form2 fh;
public Form4(Form2 caller)
{
fh = caller;
InitializeComponent();
}
private void Form4_Load(object sender, EventArgs e)
{
var instance = new ProjectM1();
instance.ProjectM1(); (error !!!)
}
}
}
So I roughly got this:
public partial class Form1 : Form
{
GameEngine engine;
public Form1()
{
engine = new GameEngine();
}
public void repaint()
{
}
}
class GameEngine
{
public void update()
{
}
}
Now i wanna add something to the update() method, which makes it call the repaint() method, inside of that instance of the Form1 class, in which the respective object of the GameEngine class was created.
In java i could've done it like this
engine = new GameEngine()
{
public void repaintCaller()
{
repaint();
}
};
and call repaintCaller() in the update() method, but that doesn't work in c#, now what is the equilvalent way to do this in c#?
One way to have it is:
public partial class Form1 : Form
{
GameEngine engine;
public Form1()
{
engine = new GameEngine();
engine.update(this);
}
public void repaint()
{
}
}
class GameEngine
{
public void update(Form1 form)
{
form.repaint();
}
}
You could pass to the GameEngine.update method an Action delegate to the repaint method in the form instance
public partial class Form1 : Form
{
GameEngine engine;
public Form1()
{
engine = new GameEngine();
// I put the call here for demo purpose,
// of course you call the engine.update
// method when you need and where you want
engine.update(repaint)
}
public void repaint()
{
Console.WriteLine("repaint called in the Form1 instance");
}
}
class GameEngine
{
public void update(Action clientUpdate)
{
if(clientUpdate != null)
clientUpdate.Invoke();
// or just... clientUpdate();
}
}
The parameterless Action delegate in C# is a way to pass, as parameter, a method (repaint) to the called method (update). Of course, you could pass the whole Form1 instance to the update but this approach binds the GameEngine class to the Form1 class. With the Action approach you are free from this coupling and you could pass any other method that returns void and doesn't take any parameter defined in any class of your program. This frees your GameEngine.update method from any specific bind to the caller.
I would try something like that
class GameEngine
{
public void update(ref Form1 caller)
{
caller.Refresh() //msdn says "Forces the control to invalidate its client area and immediately redraw itself and any child controls."
}
}
public partial class Form1 : Form
{
[...]
engine = new GameEngine()
engine.update(ref This)
}
I'm not sure of anything, i'm not used to C#.
I just hope it will help a bit :)
You can also set Events from your form, like this:
public partial class Form1 : Form
{
GameEngine engine;
public Form1()
{
InitializeComponent();
engine = new GameEngine();
engine.repaintRequired += engine_repaintRequired;
engine.update();
}
private void engine_repaintRequired(object sender, EventArgs e)
{
repaint();
}
public void repaint()
{
Console.Write("repaint");
}
}
class GameEngine
{
public event EventHandler repaintRequired;
public void update()
{
onRepaintRequired();
}
private void onRepaintRequired()
{
if (repaintRequired != null)
repaintRequired(this, new EventArgs());
}
}
I have two Projects one is a Winform application another is a Class library. I have added a reference to the class Library in Winform and called a method of the class library. Now I want to call a different method in winform application from class library but I can't add a reference to winform to the class library.
IN CODE:-
public partial class Form1 : Form
{
private void btn_Click(object sender, EventArgs e)
{
A obj = new A();
obj.foo();
}
public string Test(par)
{
//to_stuff
}
}
and in Class library
class A
{
public void foo()
{
//Do_stuff
//...
Test(Par);
//Do...
}
}
You can achieve this by injecting Test into class A.
For example:
public partial class Form1 : Form
{
private void btn_Click(object sender, EventArgs e)
{
A obj = new A();
obj.foo(Test);
}
public string Test(string par)
{
//to_stuff
}
}
class A
{
public void foo(Func<string, string> callback)
//Do_stuff
//...
if (callback != null)
{
callback(Par);
}
//Do...
}
}
While the callback method from David is a sufficient solution, if your interactions gets more complex, I would use this approach
Create an inteface in your class libary
public interface ITester
{
string Test(string value);
}
Rewrite your code so class A expects an ITester interface
public class A
{
public A(ITester tester)
{
this.tester = tester;
}
public string foo(string value)
{
return this.tester.Test(value);
}
}
Implement your interface in Form1
public partial class Form1 : Form, ITester
{
private void btn_Click(object sender, EventArgs e)
{
A obj = new A(this);
obj.foo("test");
}
public string Test(string value)
{
//to_stuff
return value;
}
}