i am trying to create a simple WPF tabbed WebControl view using Awesomium 1.7.4.2. The idea is that I have a main ClosableTab (which extends TabItem) that contains a WebControl (let's say it HomeTab) which in turn loads a certain url. From HomeTab the user can open other tabs, ie each new web page opens at a new tab item wich contains a WebControl. Each WebControl has these handlers:
webTabControl.CertificateError += webControl_CertificateError;
webTabControl.NativeViewInitialized += webControl_NativeViewInitialized;
webTabControl.ShowContextMenu += webControl_ShowContextMenu;
webTabControl.LoadingFrameComplete += webControl_LoadingFrameComplete;
webTabControl.LoadingFrameFailed += webControl_LoadingFrameFailed;
On webControl_NativeViewInitialized I create a global javascript object called DotApi and then bind some javascript methods on it such as openTab.
There is a method called JSHandler that handles the results of DotApi methods.
When DotApi.openTab is called from HomeTab, a new tab is created, added in webTabControl (tab_control) and and then shown (if user clicked with left click).
On tabItem_loaded a new webControl is created that binds the above webControl handlers and is added as content on TabItem.
If user clicked with middle click, webControl.ApplyTemplate() is called (since middle clicks, open the new tabs in the background, ie the new TabItem doesn't get focused).
It seems quite straight-forward. This works fine almost every time. The problem is that one time in hundred it comes with this error:
The specified name (DotApi), is reserved. It either represents an HTML DOM object, or an object variable already available in the page. Use ExecuteJavascriptWithResult after DocumentReady, to obtain this object.
Parameter name: name
I noticed that the above error occurs only when the error below shows up:
A first chance exception of type 'System.ArgumentException' occurred in Awesomium.Windows.Controls.dll
I looked at debug.log and noticed that this error is similar to my error with the only difference on the specified name:
The specified name (external), is reserved. It either represents an HTML DOM object, or an object variable already available in the page. Use ExecuteJavascriptWithResult after DocumentReady, to obtain this object.
Parameter name: name
My questions are:
- Why this error occurs so rarely?
- How can it be fixed?
Below is sample code to help you understand the flow:
webControl_NativeViewInitialized
private void webControl_NativeViewInitialized(object sender, WebViewEventArgs e)
{
WebControl wbControl = sender as WebControl;
try
{
JSObject jsobject = wbControl.CreateGlobalJavascriptObject("DotApi");
// openTab will be invoked each time a new page opens in new tab
jsobject.Bind("openTab", false, JSHandler);
}
catch (Exception ex)
{
Debug.WriteLine("NativeViewInitialized exception: " + ex.Message);
}
}
JSHandler
private void JSHandler(object sender, JavascriptMethodEventArgs args)
{
try
{
if (!args.MustReturnValue)
{
case #"openTab": // parameters: url, type(order,index,map), true/fasle(focus on new tab),arguments
if (args.Arguments.Length > 0)
{
Application.Current.Dispatcher.BeginInvoke(
new OpenNewTabDelegate(OpenNewTab), args.Arguments);
}
break;
}
}
catch (Exception e)
{
MessageBox.Show("JSHandler Exception: " + e.Message);
}
}
OpenNewTab
private void OpenNewTab(JSValue[] arguments)
{
try
{
ClosableTab theTabItem = new ClosableTab(this);
theTabItem.Title = "Loading";
theTabItem.Loaded += (s_, e_) => theTabItem_Loaded(theTabItem, e_, arguments);
tab_control.Items.Add(theTabItem);
if (!(bool)arguments[2]) // whether it focus on new window or not
{
theTabItem.Focus();
}
}
catch (Exception e)
{
Debug.WriteLine("OpenNewTab exception e: " + e.Message);
}
}
theTabItem_Loaded
private void theTabItem_Loaded(object sender, RoutedEventArgs e, JSValue[] arguments)
{
ClosableTab currentTab = sender as ClosableTab;
currentTab.Loaded -= (s_, e_) => theTabItem_Loaded(currentTab, e_, arguments);
WebControl webTabControl = new WebControl();
webTabControl.Source = new Uri((string)arguments[0]);
webTabControl.CertificateError += webControl_CertificateError;
webTabControl.NativeViewInitialized += webControl_NativeViewInitialized;
webTabControl.ShowContextMenu += webControl_ShowContextMenu;
webTabControl.LoadingFrameComplete += webControl_LoadingFrameComplete;
webTabControl.LoadingFrameFailed += webControl_LoadingFrameFailed;
currentTab.Content = webTabControl;
webTabControl.Dispatcher.BeginInvoke(new Action(() =>
{
// Load the webcontrol in the backgound
if(!currentTab.IsSelected){
webTabControl.ApplyTemplate();
}
}));
}
After debugging i figured out that it was a timedOut exception from awesomium. To handle it, each time i create a webControl i set its property: SynchronousMessageTimeout = 0. If you don't set it to 0 the default value will be 800ms according to current documentation SynchronousMessageTimeout
This prevented the below exceptions from appearing:
A first chance exception of type 'System.ArgumentException' occurred in Awesomium.Windows.Controls.dl
The specified name (DotApi), is reserved. It either represents an HTML DOM object, or an object variable already available in the page. Use ExecuteJavascriptWithResult after DocumentReady, to obtain this object.
Parameter name: name
Related
This is my primary way for displaying help topics from within my WinForm button click handlers:
Handler:
private void buttonHelp_Click(object sender, EventArgs e)
{
CutTools.DisplayHelpTopic(this, "create-new-viewport.htm");
}
Base method:
public static void DisplayHelpTopic(Control parent, string topic)
{
try
{
// Use an empty form as the parent so that the help file will not block the CAD software
Form mHelpParent = new Form();
// Use location of this DLL file
System.Reflection.Module mod = parent.GetType().Module;
string path = Path.GetDirectoryName(mod.FullyQualifiedName);
Help.ShowHelp(mHelpParent,
Path.Combine(path, "cut-tools-help.chm"), HelpNavigator.Topic, topic);
}
catch (System.Exception ex)
{
_AcAp.Application.ShowAlertDialog(
string.Format("\nError: {0}\nStackTrace: {1}", ex.Message, ex.StackTrace));
}
}
The forms are displaid inside AutoCAD, BricsCAD or ZWCAD. The about is fine and great. But if I want to simply display the CHM file itself (so no actual form is available) I have to do this:
[CommandMethod("TS_DisplayHelp")]
public void TS_DisplayHelp()
{
// Use location of this DLL file
System.Reflection.Module mod = GetType().Module;
System.Diagnostics.Process.Start(
Path.Combine(Path.GetDirectoryName(mod.FullyQualifiedName), "cut-tools-help.chm"));
}
It works but has one drawback. It spawns a new instance of the help and does not use the same instance.
For example:
You start one of the other commands and show the help via button click. You cancel.
You start a different command and show the help via button click. Help.ShowHelp uses same instance.
You can command and start help via TS_DISPLAYHELP and it starts new instance.
Given the context of TS_DISPLAYHELP I can't work out how to directly use Help.ShowHelp as I can in my button click handlers.
At the moment I have managed to get around this issue by duplicating the DisplayHelpTopic code directly in the command TS_DISPLAYHELP method:
[CommandMethod("TS_DisplayHelp")]
public void TS_DisplayHelp()
{
try
{
// Use an empty form as the parent so that the help file will not block the CAD software
Form mHelpParent = new Form();
// Use location of this DLL file
System.Reflection.Module mod = GetType().Module;
string path = Path.GetDirectoryName(mod.FullyQualifiedName);
Help.ShowHelp(mHelpParent,
Path.Combine(path, "cut-tools-help.chm"), HelpNavigator.Topic, "command-index.htm");
}
catch (System.Exception ex)
{
_AcAp.Application.ShowAlertDialog(
string.Format("\nError: {0}\nStackTrace: {1}", ex.Message, ex.StackTrace));
}
}
I know that my default topic is "command-index.htm".
I am happy with the above resolution.
I have these pieces of code:
private void btnPlanning_Click(object sender, RoutedEventArgs e)
{
LoadPage("PlanningView.xaml");
}
private void LoadPage(string APage)
{
try
{
frameMainView.Source = new Uri(APage, UriKind.Relative);
}
catch (Exception ex)
{
string errorString = $"Resource <{APage}> not found! ";
DoLogD(errorString + " " + ex.Message);
MessageBox.Show(errorString);
}
}
Clicking on btnPlanning button, LoadPage is called passing a string with the name of the XAML resource I want to load in the frame control frameMainView.
If the given resource doesn't not exist, I would like to catch the exception and inform the user.
The problem is that when i click the button (and the resource doesn't exist), I get in any case
PresentationFramework.pdb not loaded
and a internal System.IO.IOException telling me the resource is not available.
Why my try-catch block is not working?
there are many ways to load the pages into the frame:
By setting the source
frameMainView.Source = new Uri("PlanningView.xaml",UriKind.RelativeOrAbsolute);
By setting the Content:
frameMainView.Content= new PlanningView();
By using the NavigationService:
frameMainView.NavigationService.Navigate(new PlanningView());
It´s a user interface initialization Problem. Can you get more information from the visual Studio "Output" Window?
New to C#. Like the title, I'm having difficulty trying to raise an event. It will eventually then be consumed on another form.
What I'm trying to do is have many instances of a custom user control (my event raising form(s)) that creates a tcp client, connects, and then closes. When this tcp client has an "error", be it a catch exception, I want an event to be raised. I'm forcing the error right now by having my internet turned off to test. My first problem is I can't even get the event to be raised at all. I'll show the event code I'm working with on my custom user control:
public delegate void TaskCompleteEventHandler(object sender, TaskCompleteEventArgs e);
public event TaskCompleteEventHandler TaskComplete;
public class TaskCompleteEventArgs : System.EventArgs
{
// add local member variables to hold text
private string errorString;
// class constructor
public TaskCompleteEventArgs(string ErrorString)
{
this.errorString = ErrorString;
}
// Property
public string ErrorString
{
get
{
return errorString;
}
set
{
errorString = value;
}
}
}
This is my method that processes the exception and ideally would raise the event and allow the host form to print the string and exception accordingly.
private void ErrorLogging(string ex)
{
errorString = String.Format(/*...errorString formatting...*/);
// instance the event args and pass it the errorString value
TaskCompleteEventArgs args = new TaskCompleteEventArgs(errorString);
// raise the event with the updated arguments
TaskComplete(this, args); //----> THIS IS WHERE I GET AN ERROR!! <----
this.Dispose();
}
The error is Object reference not set to an instance of an object.
Here's the Watch screen of my TaskComplete(this, args)
I can't seem to debug this... I'm just not strong enough yet to know what I've done wrong. How is it causing side effects?
I'm sure I'm going to have more issues on my main form when I get this going... Does anyone have a clue what's causing this? Thanks in advance.
EDIT: On my main form:
public Form1()
{
InitializeComponent();
// Start control disabled and subscribe each control the event
foreach (var control in controlList)
{
control.Enabled = false;
control.TaskComplete += new dev_emu_project.dev_emu_widget.TaskCompleteEventHandler(OnTaskComplete);
}
}
List<dev_emu_project.dev_emu_widget> controlList = new List<dev_emu_project.dev_emu_widget>();
public void OnTaskComplete(object sender, dev_emu_project.TaskCompleteEventArgs e)
{
//.... work for processing
}
}
You are getting a NullReferenceException because you're invoking an empty event, meaning no delegate has been registered to it. You need to make sure TaskComplete isn't null before invoking it.
Add a null check before invoking to make sure someone did register to your event:
if (TaskComplete != null)
{
TaskComplete(this, args);
}
From MSDN Event Tutorial:
Invoking an event
Once a class has declared an event, it can treat that event just like a field of the indicated delegate type. The field will either be null, if no client has hooked up a delegate to the event, or else it refers to a delegate that should be called when the event is invoked. Thus, invoking an event is generally done by first checking for null and then calling the event
I've written an Outlook add-in (OL2010). It has a menu on the ribbon bar with various icons that open new windows that do stuff (hope that's not too in-depth ;)). An example of one of the icon Click handlers is below.
public void OnViewMyTracksClick(Office.IRibbonControl control)
{
try {
MyTracksViewModel viewModel = new MyTracksViewModel();
MyTracksView view = new MyTracksView();
view.DataContext = viewModel;
view.Show();
}
catch (Exception ex)
{
Log.Error("xxxxx", "Error on button click: " + ex.Message + Environment.NewLine + ex.InnerException);
}
}
In Outlook, if I click the button to open this view, I see the memory usage of Outlook.exe increase by 10mb (the window and it's accompanying data). When I close the view, none of that memory is reclaimed. If I click the button again, another 10mb is added, and again, none is released when I close the view.
I thought that this is because I'm creating a new viewmodel everytime, so I added some code to check if it was already instantiated (the view and viewmodel are now registered at the class level, rather that within the method, so that I don't create a new one each time) - _allTracksVM is an instantiation of AllTracksViewModel. _allTracksV is the view.
public void OnViewAllTracksClick(Office.IRibbonControl control)
{
try {
if (_allTracksVM == null)
{
_allTracksVM = new AllTracksViewModel();
}
_allTracksV = new AllTracksView();
_allTracksV.DataContext = _allTracksVM;
_allTracksV.Show();
}
catch (Exception ex)
{
Log.Error("xxxxx", "Error on button click: " + ex.Message + Environment.NewLine + ex.InnerException);
}
}
This didn't seem to make any difference. I then added an EventHandler that would fire when the view was closed:
_allTracksV.Closing += new System.ComponentModel.CancelEventHandler(this.view_RequestClose);
And this set both the objects to null (you can probably tell i'm grabbing at straws at this point):
void view_RequestClose(object sender, EventArgs e)
{
_allTracksVM = null;
_allTracksV = null;
}
The memory remains allocated. How can I dispose of the objects correctly (or perhaps I should be instantiating them differently), so that they don't consume another chunk of memory each time they are opened?
Thanks
Mick
Checking the VM for Null was a good idea but by setting it to null in the close handler, it is rendered useless :)
You could try to make the view a field in the containing class rather than a local variable. That way you don't need to create a new view each time.
As for the memory usage, it seems to me that you're doing it right. Since the GC only collects when necessary, it will take some time until the memoryusage declines.
I have few text boxes that should allow a certain format, but when a user enters it in a wrong format in a textbox, I would like to catch the control name and clear the text of the textbox.
Clearing the user input because it's not in a given format is very user-unfriendly. What if only one of ten characters was wrong? They'd have to type it all over again. Just use a MaskedTextBox with a Mask for the pattern you expect.
When using a MaskedTextBox, you can subscribe to the MaskInputRejected event as described here:
public void Form1_Load(Object sender, EventArgs e)
{
... // Other initialization code
maskedTextBox1.Mask = "00/00/0000";
maskedTextBox1.MaskInputRejected += new MaskInputRejectedEventHandler(maskedTextBox1_MaskInputRejected)
}
void maskedTextBox1_MaskInputRejected(object sender, MaskInputRejectedEventArgs e)
{
toolTip1.ToolTipTitle = "Invalid Input";
toolTip1.Show("We're sorry, but only digits (0-9) are allowed in dates.", maskedTextBox1, maskedTextBox1.Location, 5000);
}
Throwing exceptions for expected behaviour is never right as they are very expensive. If you need to see where the exception originated just check the top line of the stack trace.
debug only
you can get control name in debug mode from the yourForm.cs . i dont think this code will run on relese cuz. the source file wont be in ther release right?
using System.Diagnostics;
public void ParseControlText()
{
try
{
var doubleval = Double.Parse(tb_double.Text);
var intval = Int32.Parse(tb_int.Text);
//... bunch of controls need to be parssed to calculate something
}
catch (FormatException ex)
{
var stlast = new StackTrace(ex,true).GetFrames().Last();
//this requires form.cs to exist . how am i gonna do this in release? idk
var stLine = File.ReadLines(stlast.GetFileName())
.ToList()[stlast.GetFileLineNumber()-1];
var m = Regex.Match(stLine ,#"\((.*?)\..*?\)");
var ctrlname = m.Groups[1].Value;
MessageBox.Show( ctrlname + " control's text coundnt be Parsed! " );
}
}