How can I use pre-existing form LoadFromXml in WeifenLuo? - c#

I inherited a WinForms application where we are using Dock management with WeifenLuo. I'm trying to use the SaveAsXml and LoadFromXml.
Which works fine if I am ok with a new form every time - a particular form needs to stay available right now and I was hoping to be able to just use the code to hide it on close.
The sample app just recreates the controls every time so I'm at a loss.
If I recreate the control it shows fine. However, trying to make it use the already created control never works.
Load XML - attempt doesn't work:
m_deserializeDockContent = new DeserializeDockContent(GetContentFromPersistString);
_dockPanel = null;
InitDockPanel(); //Initialize DockPanel to full screen
_dockPanel.LoadFromXml(filepath, m_deserializeDockContent);
private IDockContent GetContentFromPersistString(string persistString)
{
if (persistString == typeof(ExistingForm).ToString())
return existingForm;
throw new NotImplementedException();
}
At this point I tried the dispose around _dockPanel and handling the dockPanel of the ExistingForm, but nothing seems to change the outcome. Reading online I discovered maybe blocking the close may help, but still doesn't work.
Example of handling the Form close event:
public ExistingForm()
{
InitializeComponent();
HideOnClose = true;
this.FormClosing += ExistingForm_FormClosing;
}
private void ExistingForm_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
this.Hide();
}
Updating LoadXml code to include existingForm.DockHandler.Close();, existingForm.DockHandler.Dispose();, or _dockPanel.Dispose();
Which doesn't work at all and I get an error because the form is disposed of.
The only thing that seems to work is recreating the form
if (persistString == typeof(ExistingForm).ToString())
return new ExistingForm();
Just wondering if I'm missing some handling of the DockHandler (no pun intended).

Related

How to implement a logging window in C#?

So using windows form builder, I have created a new form with textbox in it, calling this form as LogForm.cs, this form/class has a method called log(string text).
In my main form class (Form1.cs), I have created an instance of that form.
LogForm logForm = new LogForm();
logForm.log("Logger has started...");
and it show fine on the LogForm textbox. But when I call logForm.log("Some logging info...") On my code inside a thread, it somehow makes my application crash.
How do I deal with this? Please help me demostrate a small code.I am fairly new to C# and programming as a whole so I hope you consider.
Use/call this function in LogForm.log (btw methods in C# are usually capitalized).
private void SetText(string text)
{
Action set = () => yourTextBox.Text = text;
if (yourTextBox.InvokeRequired)
{
yourTextBox.Invoke(set);
}
else
{
set.Invoke();
}
}
If it cannot be set from the current thread yourTextBox.InvokeRequired will be true and the function will work it out. Otherwise it just sets it directly.
Inspiration from this answer at possible duplicate.
Since you are saying the problem persists I'll show a bit more code and try to expain it further.
First of all, I edited the SetText method. I added the private modifier since this function is not indended to be called anywhere outside of LogForm. I also added the curly brackets since that's my preferred style and it also makes sure that the if-statement behaves as expected.
public void Log(string message) {
SetText(message);
//do stuff
}
Both of these methods (Log and SetText) are placed inside the LogForm class. You can now call logForm.Log("Logger has started..."); from any thread as long as your form (containing the textbox) is already initialized. This usually happens in the constructor by calling InitializeComponent(); on the first line.
Without knowing more about your code this is probably as far as I can help you.

C# form is blocked after creation

I am creating a Form when a certain event occurs. I put this created Form into a static member of the class where it is created. I debugged the code and everything works fine but the Form stays blocked and the user can't do anything in this window. It just appears with a loading animation (see picture). So nothing in the opened window is clickable, you can't even close it.
class CallManagementObserver : CallObserver
{
private static FrmIncomingCall frmCurrentCall;
public CallManagementObserver()
{
}
public void callChangedEvent(CallEv[] events)
{
foreach (CallEv currentEvent in events)
{
switch (currentEvent.getID())
{
case TermConnRingingEv.ID:
// Incoming call
frmCurrentCall = new FrmIncomingCall(currentEvent);
frmCurrentCall.Show();
frmCurrentCall.Update();
break;
case CiscoCallInfoChangedEv.ID:
// User accepted external call on terminal
frmCurrentCall.Close();
break;
case TermConnActiveEv.ID:
// User is in call
frmCurrentCall.Close();
break;
case ConnDisconnectedEv.ID:
// Caller has hung up
frmCurrentCall.Close();
break;
default:
break;
}
}
}
}
}
As you can see above I wrote my own Form class whose code is here:
public partial class FrmIncomingCall : Form
{
Call incomingCall;
CallEv currentEvent;
public FrmIncomingCall(CallEv currentEvent)
{
InitializeComponent();
this.currentEvent = currentEvent;
this.incomingCall = currentEvent.getCall();
}
private void initGui()
{
Connection[] callConnections = incomingCall.getConnections();
Address caller = callConnections[1].getAddress();
lblIncomingCallSource.Text = caller.getName();
}
private void btnAcceptCall_Click(object sender, System.EventArgs e)
{
TermConnEv termConnEv = (TermConnEv)currentEvent;
TerminalConnection termConn = termConnEv.getTerminalConnection();
termConn.answer();
}
private void frmIncomingCall_Load(object sender, System.EventArgs e)
{
initGui();
}
}
When I show the Form via ShowDialog() it is usable but the program stops (since this is what dialogs are made for I guess).
Any ideas what I'm doing wrong? Nothing freezes, the program is running correctly.
Well, your application is poorly designed... It seems that you have no idea of what multithreading is and why you should use it.
If the application hangs forever, then either there is a deadlock (something like the dialog wait on the calling system and the calling system wait on the dialog).
As I have no idea what CallEv is and how it is intended to be used.
Well, if the calling system works and the UI is never updated, then obviously, you never let the UI have time to be updated because your UI thread is 100% of the time using the calling system or waiting on it.
That means that the calling system should probably be used from another thread and that you should have some communication between both threads...
It might also be possible that the calling system might be used in many different ways (as it would be the case for serial port and TCP communication) where one could use what fit most with his application.
Another problem with your code is that when you close a dialog, as far as I know it cannot be used anymore without recreating the dialog as the dialog would be disposed... So you would need to set the formCurrentCall to null and update any affected code. Alternatively, you might hide the form instead and show it again when required.
In any case, it is hard to help you because we don't have any idea of what is CallEv and other classes or events in your code. Also, we have no idea which code is executing when the UI is not responding (or updated). So the question do not have enough informations. In fact, such problem are way easier to debug using a debugger as it is far easier to see what code is run and which line of code take time to execute or even to see which code is not executed.

Trying to close a form after the next one is shown in C# cf

I've been studying Android lately and I tried to port one of its functions to C# compact framework.
What I did is create an Abstract class that I call Activity.
This class looks like this
internal abstract class Activity
{
protected Form myForm;
private static Activity myCurrentActivity = null;
private static Activity myNextActivity = null;
internal static void LoadNext(Activity nextActivity)
{
myNextActivity = nextActivity;
if (myNextActivity != null)
{
myNextActivity.Show();
if (myCurrentActivity != null)
{
myCurrentActivity.Close();
myCurrentActivity = null;
}
myCurrentActivity = myNextActivity;
myNextActivity = null;
}
}
internal void Show()
{
//PROBLEM IS HERE
Application.Run(myForm);
//myForm.Show();
//myForm.ShowDialog();
//
}
internal void Close()
{
myForm.Close();
}
internal void GenerateForm()
{
///Code that uses the Layout class to create a form, and then stores it in myForm
//then attaches click handlers on all the clickable controls in the form
//it is besides the point in this problem
}
protected abstract void Click(Control control);
//this receives all the click events from all the controls in the form
//it is besides the point in this problem
}
The problem I have is with running the part of the Show() command
Basically all my classes implement the above class, load an xml file and display it.
When I want to transition to a new class/form (for example going from ACMain to ACLogIn)
I use this code
Activity.LoadNext(new ACLogIn);
Which is supposed to load the next form, show it , and unload the current form
I have tried these solutions (in the Show() method) and here is the problem with each one
using myForm.ShowDialog()
This works, but blocks execution, which means that the old form does not close, and the more I move between the forms the more the process stack increases
using myForm.Show()
This works, closes the old form after the old one is shown, but immediately after that closes the program and terminates it
using Application.Run(myForm)
This works only on the first form loaded, when I move to the next form, it shows it then throws an exception saying "Value does not fall within the expected range"
Can someone help me fix this or find an alternative?
If you're really after creating your own framework for this navigation, you need to re-work you thinking. The Form instance passed into Application.Run must never close - when it does, Application.Run finishes execution and (typically) your static void Main entry point exits and the app terminates.
What I would propose is that you change your Activity to either being a UserControl:
public abstract class Activity : UserControl
{
....
}
or Composing one
public abstract class Activity
{
private UserControl m_control;
....
}
Then instead of closing and showing Forms, parent all of the Activities inside the main Form as a container.
As fair warning, this is going to get complex when you start wanting to show things in a Tab motif instead of a Stack, or having split views. Frameworks seem simple to create, but they're not so I'd at least consider using something already done unless you have compelling reasons to want to roll your own.
Application.Run is generally used with the overload that takes a Form parameter. This would be the "main" form that would be responsible for starting/showing other forms. This "main" form could be "hidden". But, I think that's a little awkward.
Alternatively, you don't need a main form, you can use Application.Run() to start a message pump to process Windows messages; but, then the thread is busy processing messages and cannot show dialogs (they must be shown in the thread that is running Application.Run). You can get around this by creating one or more form objects before calling Application.Run and these form objects could create a Timer object that would call Form.Show() or Form.ShowDialog() on the Timer.Tick event handler so that for form is shown after the call to Run. I think this is a little awkward as well.
Both of these solutions kind of circumvent the way you're expected to use Windows and WinForms; so, I think you need to think about re-designing this application to work with the way that Windows and .NET works.

Silverlight 4 Clipboard Security Exception "access is not allowed"?

I'm new in Silverlight and i am doing some tests. With my current test I try to display in real time the current Clipboard content. But there is a weird behaviors with this code :
namespace SilverlightTest
{
public partial class MainPage : UserControl
{
private Timer _timer;
public MainPage()
{
InitializeComponent();
var dispatcher_timer = new DispatcherTimer {Interval = new TimeSpan(0, 0, 0, 5)};
dispatcher_timer.Tick += new EventHandler(timer_Callback);
dispatcher_timer.Start();
}
private void timer_Callback(object state, EventArgs eventArgs)
{
current_clip_board.Content = Clipboard.GetText();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
current_clip_board.Content = Clipboard.GetText();
}
}
}
The button Event and the timer Event are suppose to do exactly the same action.
But it doesn't ! The Button works fine and set the clipboard text into the label but the timer throw an exception :
Clipboard access is not allowed
The question is : why ? :)
Thanks.
PS : I would bet on a thread problem :p
Clipboard access, in a partial trust (in-browser) Silverlight application (the scenario you're likely referring to above), is restricted. The GetText property is accessible only in scenarios that the Silverlight runtime determines were initiated by the user. Your example is perfect -- by a button click for example. A dispatch timer however is not user initiated, so the property throws an exception (this is especially important within the context of a in-browser application, which could be a big security hole if you could create a Silverlight application that just ran silently in the browser, watching the user's clipboard updates without their knowledge).
See this clipboard documentation for more details.
Just trigger Clipboard.ContainsText() instead of Text. The method ContainsText is allowed!
Have you tried this:
private void timer_Callback(object state, EventArgs eventArgs)
{
Dispatcher.Invoke(new System.Threading.ThreadStart(delegate()
{
current_clip_board.Content = Clipboard.GetText();
}
}
edit
After a quick search, it appears that Clipboard is only available in response to a user action see here and here.
In partial trust (the default mode for
browser-hosted Silverlight-based
applications), Silverlight also
restricts clipboard access to its two
key APIs GetText and SetText. These
APIs can only be invoked from within a
context that is determined by the
Silverlight runtime to be in response
to a user-initiated action. For
example, clipboard access is valid
from within a handler for a Click or
KeyDown event. In contrast, clipboard
access is not valid from a handler for
Loaded or from a constructor, and
access attempts throw exceptions.
If your only option is to use a timer, then don't do it at all. The clipboad is a shared resource, and you're going to raise "cannot open clipboard" errors in other programs as they try to access the clipboard. i.e. user copies something from WinWord, WinWord tries to open the clipboard, but can't, because you've got it locked while you're examining it.
Hello this works for me but only in IE Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() => HtmlPage.Window.Eval("window.clipboardData.setData('Text','testtestest')"));
just use getData method

How to show form in front in C#

Folks,
Please does anyone know how to show a Form from an otherwise invisible application, and have it get the focus (i.e. appear on top of other windows)? I'm working in C# .NET 3.5.
I suspect I've taken "completely the wrong approach"... I do not Application.Run(new TheForm ()) instead I (new TheForm()).ShowModal()... The Form is basically a modal dialogue, with a few check-boxes; a text-box, and OK and Cancel Buttons. The user ticks a checkbox and types in a description (or whatever) then presses OK, the form disappears and the process reads the user-input from the Form, Disposes it, and continues processing.
This works, except when the form is show it doesn't get the focus, instead it appears behind the "host" application, until you click on it in the taskbar (or whatever). This is a most annoying behaviour, which I predict will cause many "support calls", and the existing VB6 version doesn't have this problem, so I'm going backwards in usability... and users won't accept that (and nor should they).
So... I'm starting to think I need to rethink the whole shebang... I should show the form up front, as a "normal application" and attach the remainer of the processing to the OK-button-click event. It should work, But that will take time which I don't have (I'm already over time/budget)... so first I really need to try to make the current approach work... even by quick-and-dirty methods.
So please does anyone know how to "force" a .NET 3.5 Form (by fair means or fowl) to get the focus? I'm thinking "magic" windows API calls (I know
Twilight Zone: This only appears to be an issue at work, we're I'm using Visual Studio 2008 on Windows XP SP3... I've just failed to reproduce the problem with an SSCCE (see below) at home on Visual C# 2008 on Vista Ulimate... This works fine. Huh? WTF?
Also, I'd swear that at work yesterday showed the form when I ran the EXE, but not when F5'ed (or Ctrl-F5'ed) straight from the IDE (which I just put up with)... At home the form shows fine either way. Totaly confusterpating!
It may or may not be relevant, but Visual Studio crashed-and-burned this morning when the project was running in debug mode and editing the code "on the fly"... it got stuck what I presumed was an endless loop of error messages. The error message was something about "can't debug this project because it is not the current project, or something... So I just killed it off with process explorer. It started up again fine, and even offered to recover the "lost" file, an offer which I accepted.
using System;
using System.Windows.Forms;
namespace ShowFormOnTop {
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
Form1 frm = new Form1();
frm.ShowDialog();
}
}
}
Background: I'm porting an existing VB6 implementation to .NET... It's a "plugin" for a "client" GIS application called MapInfo. The existing client "worked invisibly" and my instructions are "to keep the new version as close as possible to the old version", which works well enough (after years of patching); it's just written in an unsupported language, so we need to port it.
About me: I'm pretty much a noob to C# and .NET generally, though I've got a bottoms wiping certificate, I have been a professional programmer for 10 years; So I sort of "know some stuff".
Any insights would be most welcome... and Thank you all for taking the time to read this far. Consiseness isn't (apparently) my forte.
Cheers. Keith.
Simply
yourForm.TopMost = true;
Form.Activate() worked in my case.
There's an overload of Form.ShowDialog() which takes an IWin32Window object. That IWin32Window is treated as the parent window for the form.
If you have the parent window as a System.Windows.Forms.Form, go ahead and just pass it. If not, get the HWND (maybe by P/Invoking to FindWindow()), and create a dummy IWin32Window implementation that just returns the HWND (More details).
You said that it works fine when you use Application.Run. Why don't you want to use Application.Run, then?
Have you tried calling BringToFront() from OnLoad or OnShown?
Activate() worked for me too.
BringToFront() did nothing in this case, I don't know why.
This is the final solution I wrote after 20 different attempts:
/* A workaround for showing a form on the foreground and with focus,
* even if it is run by a process other than the main one
*/
public static void ShowInForeground(this Form form, bool showDialog = false)
{
if (showDialog)
{
//it's an hack, thanks to http://stackoverflow.com/a/1463479/505893
form.WindowState = FormWindowState.Minimized;
form.Shown += delegate(Object sender, EventArgs e) {
((Form)sender).WindowState = FormWindowState.Normal;
};
form.ShowDialog();
}
else
{
//it's an hack, thanks to http://stackoverflow.com/a/11941579/505893
form.WindowState = FormWindowState.Minimized;
form.Show();
form.WindowState = FormWindowState.Normal;
//set focus on the first control
form.SelectNextControl(form.ActiveControl, true, true, true, true);
}
}
I've hacked this from an application I've been working on. We have a large application that loads a series of modules written by different teams. We have written one of these modules, and needed to have a login dialog open during this initialization. It was set to '.TopMost=true', but that didn't work.
It uses the WindowsFormsSynchronizationContext to open a dialog box, and then get the result of the dialog box back.
I rarely do GUI coding, and suspect this may be overkill, but it might help someone if they get stuck. I had problems with understanding how state is passed to the SendOrPostCallback, as all the examples I could find didn't use it.
Also this is taken from a working application, but I've removed several bits of code, and changed some of the details. Apologies if it doesn't compile.
public bool Dummy()
{
// create the login dialog
DummyDialogForm myDialog = new DummyDialogForm();
// How we show it depends on where we are. We might be in the main thread, or in a background thread
// (There may be better ways of doing this??)
if (SynchronizationContext.Current == null)
{
// We are in the main thread. Just display the dialog
DialogResult result = myDialog.ShowDialog();
return result == DialogResult.OK;
}
else
{
// Get the window handle of the main window of the calling process
IntPtr windowHandle = Process.GetCurrentProcess().MainWindowHandle;
if (windowHandle == IntPtr.Zero)
{
// No window displayed yet
DialogResult result = myDialog.ShowDialog();
return result == DialogResult.OK;
}
else
{
// Parent window exists on separate thread
// We want the dialog box to appear in front of the main window in the calling program
// We would like to be able to do 'myDialog.ShowDialog(windowHandleWrapper)', but that means doing something on the UI thread
object resultState = null;
WindowsFormsSynchronizationContext.Current.Send(
new SendOrPostCallback(delegate(object state) { resultState = myDialog.ShowDialog(); }), resultState);
if (resultState is DialogResult)
{
DialogResult result = (DialogResult) resultState;
return result == DialogResult.OK;
}
else
return false;
}
}
}
This did the job perfectly :
formxx.WindowState = FormWindowState.Normal;
formxx.BringToFront();
formxx.Topmost=true;
formxx.Focus();
It would appear that is behaviour is specific to XP... Hence I can't reproduce it on Vista.
http://www.gamedev.net/community/forums/topic.asp?topic_id=218484
EDIT: PS: It's past my bedtime (2 AM;-).
Thanx all for your responses... there's a "few things" I can try... I might even go into the office tomorrow to try them... Yeah, yeah... I had a life once, but I traded it for a haircut and a job ;-)
Cheers all. Keith.
I got a code in the project.
private static extern bool SetForegroundWindow(
IntPtr hWnd);
public static void ShowToFront(Form form)
{
FormWindowState oldState = form.WindowState;
form.WindowState = FormWindowState.Minimized;
form.Show();
form.Activate();
form.TopLevel = false;
form.TopLevel = true;
form.SelectNextControl(form.ActiveControl, true, true, true, true);
SetForegroundWindow(form.Handle);
form.Focus();
form.WindowState = oldState;
}
This is what I use to bring an open form that is part of my application to the front.
You can even use it with a button. But the form needs to be open or the application will break.
"YourOpenForm" has to be the name of your form from the properties window.
private void button1_Click(object sender, EventArgs e)
{
Application.OpenForms["YourOpenForm"].BringToFront();
}
Good Luck!

Categories