I have a WinForms form with, amongst other things, a WebBrowser control. I use the browser to display a preview of the file the user creates.
When the user loads a document, I want it to automatically refresh the preview window to show the new document. This works 100%.
However, I just added a "Load most recent document" feature which, as you should be able to tell, loads the last document on program start up. Although it goes through the same code path as any other method of loading a document (Open button, File->Open, File->MRU, etc), the preview does not refresh on start up.
I've followed the execution in the debugger, and all the code is being executed. However, it appears that the WebBrowser simply isn't working. If I hit the refresh button (which goes through the same code path) afterwards, it works fine.
public partial class frmMain : Form {
int scrolltop = 0, scrollleft = 0;
delegate void VoidDelegate();
private void Form1_Load(object sender, EventArgs e) {
//irrelevant initialization code omitted
//this is normally 'about:blank', but it doesn't matter anyway
html.Navigate("http://google.com");
NewFile();
if (GlobalSettings.MRU.Files.Count > 0) {
LoadFile(GlobalSettings.MRU.Files[0]);
}
}
public void NewFile() {
//misc blanking omitted
html.DocumentText = "";
}
private void LoadFile(string file) {
//file loading code omitted
//Trying to call RefreshPreview after everything else is done.
this.Invoke(new VoidDelegate(RefreshPreview));
//RefreshPreview());
}
public void RefreshPreview() {
//preserve the position if possible
if (html.Document.Body != null) {
scrolltop = html.Document.Body.ScrollTop;
scrollleft = html.Document.Body.ScrollLeft;
}
//string code = HtmlProcessing.ProcessCode(txtCode.Text, GetImageList());
string code = "If you can see this, it worked.";
html.DocumentText = code;
}
}
If you paste this code into a form named frmMain with a WebBrowser control named html, and hook up the Form1_Load event (note to self, rename this ;), you should be able to reproduce this sample. Maybe add a button that calls RefreshPreview() too.
So, short version: During Form_Load, WebBrowser doesn't do anything. Afterwards, it works fine. I need it to do something during Form_Load, what am I doing wrong?
I would recommend moving your code to the Form.Shown event. The problem is likely due to the order and timing of Form events. Since Load occurs prior to display of the form, the WebBrowser's VisibleChanged event never occurs, and I believe it is completely inactive.
Related
I have a pdf viewer which for the sake of the example, displays selected filename from a listbox.
It is a simple form with a listbox an axAcroPDF and textbox to confirm correct filepath.
The code is as follows and the files have been placed in a folder pdfs in the Debug folder:
using System;
using System.Windows.Forms;
namespace pdf_viewer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string path = AppDomain.CurrentDomain.BaseDirectory + "pdfs\\" + listBox1.SelectedItem.ToString();
textBox1.Text = path;
InitializeAdobe(path);
}
private void InitializeAdobe(string filePath)
{
axAcroPDF1.LoadFile(filePath);
axAcroPDF1.src = filePath;
axAcroPDF1.setShowToolbar(false);
axAcroPDF1.setView("Fit");
axAcroPDF1.setLayoutMode("SinglePage");
axAcroPDF1.Show();
}
}
}
It all works correctly with a few issues:
the first time you cycle through the files it displays correctly in the window but if you go back to an entry, the second time it shows the toolbar at the right despite this being disabled in the code. The toolbar takes up the bulk of the window.
When you close the window, it takes and inordinately long time to close, indicating to me there is a lot of housekeeping going on. Any clues on why this would be happening.
In addition to this:
do I need both .LoadFile and .src statements in the code as both work in isolation but is one preferable to the other. Doesn't seem to change the above issues. This method was lifted from another Stack Overflow question.
Thanks
PS Since originally posting, I have tried to display in a webBrowser window but exactly the same thing happens with the toolbar panel displaying the second time you select an entry.
The code is as follows:
webBrowser1.Url = new Uri(path);
Revisited this problem after a very long time and found the answer here
Disable Adobe Reader toolbar from my ActiveX
It appears to work in an axAcroPDF and webbrowser window.
For the axAcropdf the code to display pdf without displaying the toolbar is (using question example):
this.axAcroPDF1.src = filePath + "#toolbar=0";
this.axAcroPDF1.setView("Fit");
this.axAcroPDF1.setLayoutMode("SinglePage");
this.axAcroPDF1.Show();
For webbrowser window
InitializeAdobe(path);
webBrowser1.Url = new Uri(path + "#toolbar=0");
I have a web browser frame docked in a Silverlight application, and sometimes full-window XAML/Silverlight UI elements can pop up over it. The old problem, which I've more-or-less fixed, is that the web frame's contents didn't seem to play nice with the Silverlight content, always wanting to be rendered on top. This isn't really an issue now since I have an event that fires whenever an application-obscuring popup appears, but now there's a new problem.
My code that launches pop-ups looks like this:
public void OnModuleShown()
{
if (ModuleShown != null)
ModuleShown(this, new ModuleShownEventArgs());
}
public void ShowModule (string uri, string headerTitle, string message, string transition = "DefaultTransition")
{
// Security and destination validation
GetInfoFromURI(uri, out contentKey, out dataKey, out securityToken);
OnModuleShown();
ShowLoadingSpinner();
_loadModule(contentKey, dataKey, securityToken, headerTitle, message, transition);
}
My code that handles the event looks like this:
private void Shell_ModuleShown(object sender, ModuleShownEventArgs e)
{
if (browserFrame.Visibility == Visibility.Visible)
{
browserFrame.Visibility = Visibility.Collapsed;
return;
}
}
The new problem is that even though I call the event before I start loading and displaying the new module, and even though all the event is doing is changing a web frame's visibility, the module tends to appear first if the loading time is short. Since the module's appearance is animated, it looks even worse since the web frame seems to be waiting for the module to finish its animation before it vanishes.
Questions
Is there some kind of threading method I can use to address this? I really don't want to use Thread.Sleep but it's the only one I know of that would fix this without large program changes I can't make. Even better would be if there was a way to get this web frame to play along with Z-indexes or something similar.
I am using Visual Studio 2013, and my project's .NET Framework version is 4.0.
I am having a rather odd problem with the Gecko Webbrowser control, I have created my own class which inherits off of the Gecko Webcontrol and within the constructor of this I have set an event:
class fooGeckoClass: Gecko.GeckoWebBrowser
{
public fooGeckoClass()
{
this.DomClick += new EventHandler<Gecko.GeckoDomEventArgs>(fooEventFunction);
}
private static void fooEventFunction(Object sender, Gecko.GeckoDomEventArgs e)
{
((Gecko.GeckoWebBrowser)sender).Navigate("www.foo.com");
}
}
I am using three of these controls in a manually created UserControl, the controls are loaded in dynamically at start up from a config file and added the the UserControl controls collection. When clicking on any of the three controls, all three will navigate to "www.foo.com" away from there original site. I had a look at:
e.StopPropagation();
Which specifies that it stops further propagation of events during an event flow, however it does also specify that it will handle all events in the current flow, I believe the events must have already been given to the controls before this has a chance to stop it as the the three controls will still fire the event. I also tried e.Handled = true to no avail. Has anyone encountered this problem before and have any kind of solution to make it only fire on the control that was clicked on?
EDIT:
It may be worth showing how the controls are added to the form seeing as this must be where the problem is occurring (it does not happen if the controls are just placed in a user control in a small test app).
private void fooUserControl_Load(object sender, EventArgs e)
{
if (!this.DesignMode)
{
for (int iControls = 0; iControls < geckObs.Count(); iControls ++)
{
fooGeckoClass geckControl = new fooGeckoClass();
this.Controls.Add(geckControl );
break;
}
}
}
Odd answer but I seem to have resolved the issue, DomClick was being called at first run, changing to DomMouseClick or DomMouseUp has completely resolved the issue. I assume DomClick must be an event unto itself as it also doesn't use the GeckoDomMouseEventArgs but the regular GeckoEventArgs.
EDIT:
To add to this, the site I was going to was actually calling DomClick when it had finished loading hence the reason it was being called at start up across all three browsers.
I have a custom Winform Infopath UserControl which loads a form from a sharepoint library. I have a series of function calls, after opening the form, to pull some data from the form, even a take screenshot function. But the form load takes a lot of time, and the other functions finish up too quickly, much before the form load, which gives me wrong results.
Is there any way I can have a wait function, that waits for the infopath form to finish loading before the other functions are called?(in c#)
--Update
Example Code:
Inside the UserControl, I have a form initialize function, that basically loads the form
public void InitializeInfoPathForm(string myurl)
{
if (this.IsInitialized) return;
CreateForm(new Uri(myurl),null);
}
public void CreateForm(
Uri formUrlName,
Stream dataStream)
{
TestInitialization();
try
{
this.formControl.Close();
// Open / create a form
if (dataStream != null)
formControl.Open(
formUrlName.ToString()
);
else
{
formControl.Open(
formUrlName.ToString());
}
RefreshView(UIStatesForm.DocumentReadMode);
}
catch (Exception)
{
RefreshView(UIStatesForm.NoDocumentAvailable);
throw;
}
}
The Winform looks like this:
public partial class Form1 : Form
{
public Form1(string sharepoint_url)
{
InitializeComponent();
this.infoPathUserControl1.InitializeInfoPathForm(sharepoint_url);
takescreenshot();
}
}
I tried putting the takescreenshot() in a Form1_Load and Form1_Shown eventhandlers, but still the screenshots occur much earlier than the form load because FormControl.Open() takes a lot of time. I could put the screenshot function in a button_click event, but i want to automate this procedure. I even tried putting it ina button_click procedure and called button.PerformClick from the Form_Load eventhandler.
Pls Advice.
You use the event UserControl.Activated for the purpose
UserControl1.Activated += new EventHandler(SeriesOfFunctions);
Then write your code in this SeriesOfFunctions
You have other choices like UserControl.Load,UserControl.Activating
You can define a bool and set it to false, after your infopath has been loaded, set it to true and only in that case start the intialize_component in your form constructor. or something like that!
If I am understanding your question correctly, it seems as though you are running into a race condition where you have tasks executing on separate threads.
If you can... I'd use the On_Load function of the Form; however, if you need to have separate threads for speed so that the background tasks don't have to wait for the form prior to starting, take a look at the ManualResetEvent. You could have the form.on_load event call set on the event once it is correctly loaded.
So I've got some serious problems with removing a Control from a Form of my application. It's kinda messed up but I can't change anything. I have a form and I have a separated user Control. The control opens an exe file and shows a progress bar while loading it's bytes. And here comes the problem. I do all of it with a BackgroundWorker and when the worker_DoWorkerCompleted method is called the original form should show a MessageBox and remove the Control.
BackGround_Loader bgLoad = new BackGround_Loader();
bgLoad.Location = new Point(this.Width/2 - bgLoad.Width/2, this.Height/2 - bgLoad.Height/2);
this.Controls.Add(bgLoad);
bgLoad.BringToFront();
bgLoad.AddReferences(this.executableFile, this.SourceReader);
bgLoad.occuredEvent();
At first I set the control's location to be in the middle of the Form itself. Then I add the control to the form, and bring it to the front. After these I send the path of the executable and a RichTextBox's reference to this. With the occuredEvent I start the BackgroundWorker itself. And here comes my problem. I should show a MessageBox in the Form when the in the bgLoad the backgroundworker gets to the DoWorkerCompleted status. Kindly I have no idea how to do it. It works just perfect however the control stays in the middle of the form.
UI actions must be performed on the main UI thread. The events that get raised from the background worker thread are (obviously) in a different thread.
You need something like the following code:
private void backgroundWorker_DoWork(object sender, AlbumInfoEventArgs e)
{
// Check with an element on the form whether this is a cross thread call
if (dataGridView.InvokeRequired)
{
dataGridView.Invoke((MethodInvoker)delegate { AddToGrid(e.AlbumInfo); });
}
else
{
AddToGrid(e.AlbumInfo);
}
}
In this case AddToGrid is my method for adding a row to a DataGridView, but in your case it will be a method that does what you need to do.
Similarly for the backgroundWorker_RunWorkerCompleted method
See this MSDN example
I could find a way to solve the problem but I don't really like it. In the addReferences method I pass the Form itself and an object of the bgLoad class. Then in the RunWorkerCompleted I check if the control is on the form and if it is then I remove it.
bgLoad.AddReferences(this, bgLoad, this.executableFile, this.SourceReader);
...
private void worker_DoWorkerCompleted(object sender, DoWorkerEventArgs e) {
if(this.MainForm.Controls.Contains(this.Control) {
this.MainForm.Controls.Remove(this.Control);
}
}
Like this it works but it's awful for me.