Awesomium WebControl trouble with Enable Control in Winform c# - c#

I would use this Browser Framework in my Winform Application c#.
I just Saw the Documentation HERE
So i would use this Method
I just create a new Class and a new Awesomium.Windows.Forms.WebControl Object.
Now if i use it without any particulary method (just the ones to create object and Load the Url Source it works. But when i want use This method :
browser.SetHeaderDefinition("MyHeader", myCol); //myCol is a NameValueCollection
i recive this error The control is disabled either manually or it has been destroyed.
On the first page that i linked there is wrote :
In addition to its regular meaning, the Enabled property has a special meaning in WebControl: it also indicates if the underlying view is valid and enabled.
A WebControl is considered invalid when it has been destroyed (by either calling Close() or Shutdown()) or was never properly instantiated.
Manually setting the Enabled property to true, will temporarily render the control disabled.
....
....
While disabled (either because the view is destroyed or because you manually set this property) attempting to access members of this control, may cause a InvalidOperationException (see the documentation of each member).
Now i tried to play with the ENABLED property but i still get this error. What i have to do to resolve this problem? I really didn't understand.
Awesomium.Windows.Forms.WebControl browser =
new Awesomium.Windows.Forms.WebControl();
this.SuspendLayout();
browser.Location = new System.Drawing.Point(1, 12);
browser.Name = "webControl1";
browser.Size = new System.Drawing.Size(624, 442);
browser.Source = new System.Uri("http://www.google.it", System.UriKind.Absolute);
browser.TabIndex = 0;
**** This below is the code that i cant use cause i get the error control
// System.Collections.Specialized.NameValueCollection myCol =
// new System.Collections.Specialized.NameValueCollection();
// myCol.Add("Referer", "http://www.yahoo.com");
// browser.SetHeaderDefinition("MyHeader", myCol);
// browser.AddHeaderRewriteRule("http://*", "MyHeader");

The issue is that you cannot set the header definition until the control has finished being created. You just need to delay when you're setting the header definition until the control is ready. I'm not a Winforms expert, so there may be a better event to use to determine where a control is in its lifecycle, but here's a working modification of what you posted that just uses the control's Paint event to defer the problematic method calls:
public partial class Form1 : Form
{
private Awesomium.Windows.Forms.WebControl browser;
public Form1()
{
InitializeComponent();
browser = new Awesomium.Windows.Forms.WebControl();
//delay until control is ready
browser.Paint += browser_Paint;
Controls.Add(browser);
browser.Location = new System.Drawing.Point(1, 12);
browser.Name = "webControl1";
browser.Size = new System.Drawing.Size(624, 442);
browser.Source = new System.Uri("http://www.google.it", System.UriKind.Absolute);
browser.TabIndex = 0;
}
void browser_Paint(object sender, PaintEventArgs e)
{
browser.Paint -= browser_Paint;
System.Collections.Specialized.NameValueCollection myCol =
new System.Collections.Specialized.NameValueCollection();
myCol.Add("Referer", "http://www.yahoo.com");
browser.SetHeaderDefinition("MyHeader", myCol);
browser.AddHeaderRewriteRule("http://*", "MyHeader");
}
}

Related

WinForm TabControl tab page contents does not update until the new tab is shown

I have a tabcontrol which allows the creation of new tabs. Each new tab has a web browser control CEFSharp on it. When the new tab is created it is not shown the previously opened tab is shown; which is what we want.
However, the browser on the newly created tab is only added to the tab page, and only partially runs... it does not go to the loading state until the tab page is shown.
Here is the Tabpage creation code:
private void AddNewBrowser()
{
Log("Adding New Tab and Browser");
UiBrowser browser = new UiBrowser();
TabPage tp = new TabPage();
tp.Controls.Add(browser);
customTabControl1.TabPages.Add(tp);
}
The UiBrowser is a UserControl which contains the CEFSharp Browser Control plus some extra UI.
And here is the Startup code for the Browser itself.
private void UiBrowser_Load(object sender, EventArgs e)
{
Execute();
}
private void Execute()
{
webBrowser = new ChromiumWebBrowser("http://google.co.uk")
{
Dock = DockStyle.Fill,
Text = "Loading...",
Tag = Tag
};
webBrowser.TitleChanged += Browser_TitleChanged;
webBrowser.AddressChanged += Browser_AddressChanged;
webBrowser.ConsoleMessage += Browser_ConsoleMessage;
webBrowser.LoadingStateChanged += Browser_LoadingStateChanged;
webBrowser.StatusMessage += Browser_StatusMessage;
browserPanel.Controls.Add(webBrowser);
Application.DoEvents();
}
The code has been simplified for clarity and I have not found a solution on SO or elsewhere for this problem.
Question:
How do I get the browser control to load the webpage whilst remaining in the background? That is while the TabPage that the control is on is NOT shown to the user.
The Load event will only happen when the control becomes visible the first time:
Occurs before the control becomes visible for the first time.
so try moving your Execute method into the UserControl's constructor code.
There is no "official" way of doing that.
But if you really need it and don't afraid using internals, you may take a look at my answer to WinForms: Respond to BindingSource being applied.
The solution (or hack) is encapsulated in this little helper
public static class ControlUtils
{
static readonly Action<Control, bool> CreateControlFunc = (Action<Control, bool>)Delegate.CreateDelegate(typeof(Action<Control, bool>),
typeof(Control).GetMethod("CreateControl", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(bool) }, null));
public static void CreateControls(this Control target)
{
if (!target.Created)
CreateControlFunc(target, true);
else
for (int i = 0; i < target.Controls.Count; i++)
target.Controls[i].CreateControls();
}
}
At the end of your form load event, add the following
this.CreateControls();
or
customTabControl1.CreateControls();
and also here
private void AddNewBrowser()
{
Log("Adding New Tab and Browser");
UiBrowser browser = new UiBrowser();
TabPage tp = new TabPage();
tp.Controls.Add(browser);
customTabControl1.TabPages.Add(tp);
if (customTabControl1.Created)
tp.CreateControls();
}

How can I pass a parameter to control event handler?

I am creating a winforms app which generates a number of panels at runtime. I want each panel, when clicked, to open a web link.
The panels are generated at runtime:
for (int i = 0; i < meetings.Count(); i++) {
Panel door = new Panel();
door.Location = new System.Drawing.Point((i * 146) + (i * 10) + 10, 10);
door.Size = new System.Drawing.Size(146, 300);
door.BackgroundImage = ConferenceToolkit.Properties.Resources.Door;
door.Click += new EventHandler(door_Click);
Controls.Add(door);
}
and I want the event handler to point to a URL that is stored somehow in the Panel attributes. (On a web form I could use Attributes["myAttribute"] but this doesn't seem to work with WinForms):
private void door_Click(object sender, EventArgs e)
{
Panel p = sender as Panel;
Process.Start(p.Attributes["url"]);
}
There are many options for this, you may store URL in the (unused in Panel) Text property:
door.Text = FindUrl(meetings[i]);
Used like:
Process.Start(p.Text);
As alternative you may use general purpose Tag property:
door.Tag = FindUrl(meetings[i]);
With:
Process.Start(p.Tag.ToString());
Tag property is usually right place for these things and, becauase it's of type object, you can even use it to store complex types (in case you need more than a simple string).
See also similar posts for slightly more complex cases: this, this and this.
You can store the URL that you want in the Panel's Tag propertie
for example
p.Tag = "www.google.com";
and then you can use it when use cast the Panel in the on click method
reference for the .Tag property
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.tag(v=vs.110).aspx

Why "this" works but "Form.Activeform" throws NullRefernceException?

if this keyword refers to the current instance of the class as instanced in program class(Application.Run(new Form1()))
we can reach it's properties with this keyword
this .Text = "debuggging";
this .Opacity = 54;
this .ShowIcon = true;
this .Size = new Size(100, 100);
why cant ı reach it with Form1.ActiveForm.*(All properties)
just out of curiosity but why
when coded like this
Form1.ActiveForm.Text = "debugla";
Form1.ActiveForm.Opacity = 54;
Form1.ActiveForm.ShowIcon = true;
Form1.ActiveForm.Size = new Size(100, 100);
and activeform must bring us the currently active form used
it throws nullreference exception why ?
MSDN: Form.ActiveForm: "A Form that represents the currently active form, or null if there is no active form."
So maybe because you are debugging the form is not active(has not focus), therefore it returns null.
ActiveForm returns the active form... this means that if your window doesn't have focus, then it is not active. Therefore by using it in this way you greatly risk your program producing an error.
Using this ensures you are accessing the form you are intending to change
You should also note that ActiveForm is a static property and therefore it has no link whatsoever to the form you are using it in if you have any other windows open in your application then your changes could apply to these other dialogs
You can do this:
Form currentForm = Form.ActiveForm;
if(currentForm != null)
{
//use currentForm properties
}
Form.ActiveFormgets the currently active form for this application.
while this refers to current instance of Form1.

Form passing null value

I have fixed my form load problem. I changed it to where the main menu wasn't being called on load event and that fixed the issue. Now my retrieve event gets the version but never passes it to my form.
Here is my code for transferring process:
Where the information is being pulled from:
public string VersionPass { get; set; }
VersionPass = rtxtBoxNewVersion.Text;
This is the main menu where the value will be stored till they click the assign button. This is where it gets the value from the form.
public string VersionNum { get; set; }
VersionEditor newV = new VersionEditor();
newV.ShowDialog();
VersionNum = newV.VersionPass;
newV.Dispose();
Form being transferred to I am using form load because the value will not change: It never get the value into the PassedVersion = passedVersion.VersionNum; field.
MainMenu passedVersion = new MainMenu()
string PassedVersion;
private void Notification_Load(object sender, EventArgs e)
{
PassedVersion = passedVersion.VersionNum;
rTxtBoxVersion.Text = PassedVersion;
}
Having to guess a bit here, but ...
1) Take out new MainMenu() from the Notification_Load call. This is probably stopping the dialog being created properly.
2) If you want to share information you either need to pass it to the new object, for example when you create it:
MyObject = new MyClass(SomeObjectToTellItAbout);
// or maybe like this:
MyObject.InterestingInfo = SomeOtherObject;
If it's truely global information (app version, for example) you could make the info to share static (and then access it like this: MainMenu.MyAppVersion).
Edit based on comments:
You want to get an understanding of classes vs objects. A class is just a design; it's a concept. For example "human". An object is an instantiation of that class/concept/design, for example me. And you (another object). I can't find your name by saying h = new human(); h.name() and nor can you find your version by making a new MainMenu and asking it what version it is! Hope that helps.

Persisting User Input for Dynamic Control in SharePoint Web Part

Edit at bottom with solution
I've seen a similar question to this posted before and have tried the suggestions, but I must be missing something. My basic problem is this: I have a select box where the user can select a filter which may or may not have constraints built into it (requires the user to input further data so the filter knows how to filter). Since it's unknown just how many constraints will exist for the filter, I'm trying to load them in dynamically and add them to a placeholder panel that I have. The correct number of constraints load just fine and dandy, but when the user inputs text and hits submit, after the page reloads none of the values persist. Here's the appropriate code (I can provide more if needed):
I have these as class variables for my Web Part:
Panel constraintPanel;
HtmlInputText[] constraints;
Label[] constraintLabels = null;
Inside an override CreateChildControls I initialize the panel:
constraintPanel = new Panel();
I build in the dynamic input boxes in an overridden OnPreRender (Note: I've heard people say to do it in OnInit, OnLoad, or OnPreRender, but OnPreRender is the only one that doesn't make the whole Web Part error out):
protected override void OnPreRender(EventArgs e)
{
buildConstraints();
base.OnPreRender(e);
}
private void buildConstraints()
{
if (!viewSelect.SelectedValue.Equals(INConstants.NoFilterOption))
{
string[,] constraintList = docManager.GetFilterConstraints(viewFilterSelect.SelectedValue);
if (constraintList != null)
{
this.constraints = new HtmlInputText[constraintList.Length / 2];
this.constraintLabels = new Label[constraintList.Length / 2];
for (int constraintCount = 0; constraintCount < constraintList.Length / 2; constraintCount++)
{
Label constraintLabel = new Label();
constraintPanel.Controls.Add(constraintLabel);
constraintLabel.Text = constraintList[constraintCount, 0];
this.constraintLabels[constraintCount] = constraintLabel;
HtmlInputText constraint = new HtmlInputText();
constraintPanel.Controls.Add(constraint);
constraint.ID = "constraint_" + constraintCount;
constraint.MaxLength = 12;
constraint.Style.Add("FONT-FAMILY", "Verdana");
constraint.Style.Add("FONT-SIZE", "11");
this.constraints[constraintCount] = constraint;
}
}
}
}
And then finally inside an overridden RenderWebParts I have (note: I've also tried looping through the arrays constraints and constraintLabels to render the controls, but it made no difference):
...
constraintPanel.RenderBeginTag(output); // not sure if this is needed
if (constraints != null && constraints.Length > 0)
{
foreach (Control tempControl in constraintPanel.Controls)
{
if (tempControl is Label)
{
output.WriteLine("<tr>");
output.WriteLine("<td width='2%' nowrap><font class='search-header'>");
tempControl.RenderControl(output);
output.WriteLine(" ");
}
else if (tempControl is HtmlInputText)
{
tempControl.RenderControl(output);
output.WriteLine("</td>");
output.WriteLine("<td width='*' nowrap></td>");
output.WriteLine("</tr>");
}
}
}
constraintPanel.RenderEndTag(output); // not sure if this is needed
...
I appreciate any help, as this is truly driving me crazy.
Edit with solution:
I've been able to get it working. I needed to override the OnLoad event and wrap my calls from there in a try-catch block. For some reason the initial page load throws an exception when trying to run, which causes the entire page to not display. I also forgot to add my constraintPanel to the Controls list.
Here's the code in OnLoad for information's sake:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
try
{
viewsBuildConstraints();
}
catch (Exception)
{
}
}
Try marking your webpart with the INamingContainer interface and make sure to give all controls an ID. Furthermore, HtmlInput COntrols do not have a viewstate i believe, which would cause them to "forget" the input after a postback. Could you try using actual TextBox controls?

Categories