Nothing happening when you click second time - c#

I having terrible when i execute the same method second time.i am not getting WPF screen, I don't know why?
refer my code
TestWindow Button click method(it is windows application project type) and i have removed STA thread in my
Main()
TestClass test;
private void button1_Click(object sender, EventArgs e)
{
test =TestClass.Instance; //singleton pattern
test.ShowScreen();
}
TestClass
public void ShowScreen()
{
var thread = new Thread(() =>
{
Explorer explorer = new Explorer();
explorer.Show();
explorer.Closed += (s, args) =>
explorer.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
Above the code working fine when i run 1st time. i can able view my explorer screen.
But the problem is when i close 1st screen and call once again the same method(test.ShowScreen();) the explorer screen not showing
Note : I have noticed If i didn't close the 1st window(instance) then i can able open many explorer screen. using the same code. If i closed the 1st window(instance) and i am unable open explorer screen and i am not getting any error message.

The issue is resolved Adding the following line in the TestClass Constructors
using SW = System.Windows;
private TestClass()
{
if (SW.Application.Current == null)
{
new SW.Application
{
ShutdownMode = SW.ShutdownMode.OnExplicitShutdown
};
}
}

Related

How to show a WPF window from Class Library (dll) project?

I have recently made a Class Library (dll) for my other project to program a Bluetooth device via serial port (COM). The library is used to transfer firmware via COM port. It works fine until the requirement comes, which requires a WPF window to show the progress of programming. I have successfully created the progress bar using standard WPF app template. However, the standard WPF does not allow me to generate dll. After searching here, I found this link that teaches you how to add a WPF window to existing Class Library project. Also, someone teaches you how to show the window from here. Everything look good until I tried, there is nothing shows up when I call the method ProgrammBluetooth() from LabVIEW.
My main method, which is in a separate .cs file:
namespace BTMProg
{
public class BTMProgrammer
{
private bool _uut1Status = false;
private string _uut1Message = "";
public bool UUT1Status
{
get { return _uut1Status; }
set { _uut1Status = value; }
}
public string UUT1Message
{
get { return _uut1Message; }
set { _uut1Message = value; }
}
public void ProgramBluetooth (string ioPort, string firmwareFile)
{
List<UUT> uutList = new List<UUT>();
uutList.Add(new UUT(ioPort, "UUT1", 1));
Thread thread = new Thread(() =>
{
var wn = new MainWindow(uutList, firmwareFile);
wn.ShowDialog();
wn.Closed += (s, e) => wn.Dispatcher.InvokeShutdown();
Dispatcher.Run();
if (wn.TaskList[0].Result.ToUpper().Contains("SUCCESS"))
{
_uut1Status = true;
_uut1Message = wn.TaskList[0].Result;
}
else
{
_uut1Status = false;
_uut1Message = wn.TaskList[0].Result;
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
}
}
My WPF code in MainWindow.xaml.cs:
ProgrammingViewModel _pvm = new ProgrammingViewModel();
private List<string> _viewModeList = new List<string>();
private List<Task<string>> _taskList = new List<Task<string>>();
public List<Task<string>> TaskList {
get => _taskList;
set => _taskList = value;
}
public MainWindow(List<UUT> uutList, string firmwareFile)
{
InitializeComponent();
foreach (var uut in uutList)
{
_viewModeList.Add(uut.UutName);
}
_pvm.AddProcessViewModels(_viewModeList);
ProgressBarView.DataContext = _pvm.ProcessModels;
StartProgramming(uutList, firmwareFile);
Application.Current.MainWindow.Close();
}
The issue before was that if I don't use dispatcher to create a new thread, an exception saying "The calling thread must be STA, because many UI components require this...." thrown. After I use the new thread, no error but the window does not show up as expected. What could be the problem? Thanks.
The ShowDialog function will stop execution of the thread until the window closes, meaning the rest of that code may not run and the dispatcher may not be started. You should try the Show method instead, which returns as soon as the window is shown.
Also, what is going on with these lines in the constructor of the window?
StartProgramming(uutList, firmwareFile);
Application.Current.MainWindow.Close();
Whatever that first line does, it needs to return and not do a bunch of work if you want the window to finish getting constructed. The second line makes no sense at all. Why are you closing the main window of the application? Did you even set and open a window associated with that property at some point?
I suspect one or more of these things is preventing the thread from ever reaching the point where it can show the window.

Can't load website in CefSharp

I'm trying to load a website URL using RegisterJsObject in one of two cefsharp instances. The URL is received from the website (chromeBrowser1) however It wont update the window (chromeBrowser2). I tried to document the script as much as possible so it would be more easy to understand. I'm pretty sure somebody with general knowledge in C# will find my problem, I spend hours trying to find a solution but I just couldn't.
private void Form1_Load(object sender, EventArgs e)
{
CefSettings settings = new CefSettings();
Cef.Initialize(settings);
chromeBrowser2 = new ChromiumWebBrowser("http://google.com") // Initializate Browser 2 FIRST ( This is the instance we want to update every X seconds using chromeBrowser2.Load("http://somewebsite.com"); later on )
{
Dock = DockStyle.Fill,
};
splitContainer1.Panel2.Controls.Add(chromeBrowser2);
chromeBrowser1 = new ChromiumWebBrowser("http://127.0.0.1/") // Initializate Browser 1 - Main website - source of data and more
{
Dock = DockStyle.Fill,
};
splitContainer1.Panel1.Controls.Add(chromeBrowser1);
chromeBrowser1.RegisterJsObject("callbackObj", new CallbackObjectForJs()); /// the link is obtained from here - See picture
}
public class CallbackObjectForJs
{
private readonly static BackgroundWorker backgroundWorker1 = new BackgroundWorker();
private readonly static ChromiumWebBrowser chromeBrowser2 = new ChromiumWebBrowser("http://facebook.com");
// IF I REMOVE ANY OF THE ABOVE I WILL RECEIVE THE FOLLOWING ERROR :
// Error CS0120 An object reference is required for the non-static field, method, or property 'Form1.backgroundWorker1'
// Error CS0120 An object reference is required for the non-static field, method, or property 'Form1.chromeBrowser2'
public void showMessage(string msg)
{
var sitelink = msg;
Console.WriteLine(sitelink); // WORKING - link is visible on console but chromeBrowser 2 is not update, still reads http://google.com
Console.WriteLine("Loading site using one of the options below"); // Can be seen on console +
// AT THIS POINT chromeBrowser2 SHOULD LOAD THE NEW URL ///
chromeBrowser2.Load(sitelink); // NOT WORKING
Console.WriteLine("Check Point 1");
backgroundWorker1.RunWorkerAsync(sitelink); // NOT WORKING
Console.WriteLine("Check Point 2");
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) // NOT WORKING
{
Console.WriteLine("Background Worker"); // Nothing
string link = (string)e.Argument;
Console.WriteLine("Check Point 3");
chromeBrowser2.Load(link);
Console.WriteLine("Check Point 5");
Console.WriteLine(link);
Console.WriteLine("Check Point 6");
}
Console results.
I understand that, for some reason, neither of the option I've chosen are being triggered. I have high speculations that is because of Error CS0120, which I managed to hide with making them static but that's it pretty much. I'm out of ideas. Search results got me this far.
I installed ReSharper and it found the problem in less than a minute.
All I had to do is make chromeBrowser2 static.
public partial class Form1 : Form
{
public ChromiumWebBrowser chromeBrowser1;
public *static* ChromiumWebBrowser chromeBrowser2;
....
Thanks for any input.

Display my forms in another class

I recently developped an application for a student project, and everything works fine. However, if I'm asking something here, you can certainly assume that the whole thing isn't so functional...and you'd be right hohoho. Let's get started. Basically the functional version of my project uses an UI console.
It runs, but from an user point of view, working with something like this isn't the most amazing stuff in the world. So I decided to replace my old console by some Windows Forms.
Project global render with console
Project global render with form
This is where things become wrong. I have "3" classes :
Program.cs (the main program with all the serious stuff)
formOne.cs (the first form with a button for each options)
form/Two to Five/.cs (each options open the corresponding form)
At some point, Program.cs will launch formOne.cs, and from there the user should be able to navigate between the various options and so the various forms...but nope. formOne.cs opens, and then we can't click on anything (well we can but nothing happens). I did a mistake somewhere, I would like to know where and how to fix it. Here's how I proceeded :
(this is the basic algorithm, not the whole code)
Program.cs :
class Program {
formOne winRecep = new formOne();
formTwo winCrea = new formTwo();
formThree winSearch = new formThree();
formFour winDel = new formFour();
formFive winView = new formFive();
winRecep.ShowDialog();
string userChoice = winRecep.getUserChoice();
switch(userChoice){
case "create new task" :
winCrea.ShowDialog();
break;
case "search a task" :
winSearch.ShowDialog();
break;
case "delete a task" :
winDel.ShowDialog();
break;
case "view my tasks" :
winView.ShowDialog();
break;
}
}
formOne.cs :
class formOne {
string userChoice;
public formOne()
{
InitializeComponent();
}
public string getUserChoice()
{
return userChoice;
}
private void formOne_Load(object sender, EventArgs e)
{
//blabla update current date, current hour...
}
private void buttonOptionOne_Click(object sender, EventArgs e)
{
userChoice = "create new task";
}
private void buttonOptionTwo_Click(object sender, EventArgs e)
{
userChoice = "search a task";
}
private void buttonOptionThree_Click(object sender, EventArgs e)
{
userChoice = "delete a task";
}
private void buttonOptionFour_Click(object sender, EventArgs e)
{
userChoice = "view my tasks";
}
}
It seems pretty clear to me, but I did a mistake somewhere. I would like to work in Program.cs instead of formOne.cs because, well, everything is in Program.cs so the most logical way to proceed is certainly to work here instead of bring informations and variables everywhere accross the classes.
Could someone help me and explain why it's wrong ?
EDIT : Program.cs using Application doesn't solve the thing :
class Program {
var winRecep = new formOne();
var createtask = new formTwo();
var viewTask = new formThree();
var searchTask = new formFour();
var deleteTask = new formFive();
Application.Run(winRecep);
string userChoice = winRecep.getUserChoice();
switch(userChoice){
case "create new task" :
Application.Run(createtask);
break;
case "search a task" :
Application.Run(searchTask);
break;
case "delete a task" :
Application.Run(deleteTask);
break;
case "view my tasks" :
Application.Run(viewTask);
break;
}
}
You need to start your main form like this:
var mainForm = new formOne();
Application.Run(mainForm);
This starts the windows message loop. Without a message loop, your application can't respond to any events (such as mouse clicks or keypresses).
The first thing you should do, is opening the main form using Application.Run, as already suggested. This starts the message loop which is essential for the rest of the execution:
var mainForm = new formOne();
Application.Run(mainForm);
Then use that form to open all others. Closing the form started with Application.Run will close the application since the message loop will end too. So on any action, like a button click or a command written, open the form you need. You can call Show to open the other form and make it possible to still access the main form, or ShowDialog which will block further actions until the child form was closed.

Directx device doesn't initialize for window, Program hang

I've tried following several tutorials an have seem to be having trouble.
I've got an existing program that i'm trying to add a directx window to as an additional popup forum that will run as a child to the main application form.
Here is the windows form class:
public partial class DxWindow : Form
{
Device device;
public DxWindow()
{
InitializeComponent();
initDevice();
}
private void initDevice()
{
MessageBox.Show("hello");
PresentParameters pp = new PresentParameters();
pp.Windowed = true;
pp.SwapEffect = SwapEffect.Discard;
device = new Device(0, DeviceType.Hardware, this, CreateFlags.HardwareVertexProcessing, pp);
}
private void Render()
{
//render stuff
}
private void DxWindow_Paint(object sender, PaintEventArgs e)
{
Render();
}
}
and here is where i initialize the form (from a UI button in main window)
private void toolStripButton3_Click_1(object sender, EventArgs e)
{
if (DirectxWindow == null)
{
DirectxWindow = new DxWindow();
DirectxWindow.Show();
}
}
When i run the program and click the button. it seems create the form in memory but never shows up. when i step through it in the debugger, it gets to "DirectxWindow = new DxWindow();" and then automatically jumps out of break mode and continues running with the main window frozen and no new Dxwindow().
when i break execution is seems to still be on "DirectxWindow = new DxWindow();"
Also, "MessageBox.Show("hello");" in the DxWindow constructor is never called"
Edit: I've deduced that as soon as it hits "PresentParameters pp = new Microsoft.DirectX.Direct3D.PresentParameters();" the application becomes unresponsive without throwing any errors.
Turns out my problem was needing to use
<startup useLegacyV2RuntimeActivationPolicy="true">
in the "App.config" File
Solution was found here: Mixed mode assembly is built against version 'v1.1.4322'
Although i never got the error as described by the OP. i simply had this problem as described in the comments:
"Thank you!!!! This is the weirdest problem I'd ever encountered. In VS 2012 .Net 4.0 my application would just hang the moment I initialized any variable of a type related to this DLL. I'd never seen anything like it. Couldn't find anything about the problem until I found this!" – Quinxy von Besiex

Re-Open WPF Window from a Console application

I want to open a WPF Window from a Console application. After referring to this post, it works fine.
The problem is: When the user closed the WPF Window (manually), it can no long be re-opened from the Console, throwing the exception message: "Cannot create more than one System.Windows.Application instance in the same AppDomain."
Here is the code:
class Program
{
static void Main(string[] args)
{
string input=null;
while ((input = Console.ReadLine()) == "y")
{
//Works fine at the first iteration,
//But failed at the second iteration.
StartWpfThread();
}
}
private static void OpenWindow()
{
//Exception(Cannot create more than one System.Windows.Application instance in the same AppDomain.)
//is thrown at the second iteration.
var app = new System.Windows.Application();
var window = new System.Windows.Window();
app.Run(window);
//User closes the opened window manually.
}
private static void StartWpfThread()
{
var thread = new Thread(() =>
{
OpenWindow();
});
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = false;
thread.Start();
}
}
How can I re-open the WPF Window?
You should not create the application together with the window but only once separately, also make sure that it does not exit after the window is closed by setting the ShutdownMode respectively, e.g.
class Program
{
static Application app;
static void Main(string[] args)
{
var appthread = new Thread(new ThreadStart(() =>
{
app = new Application();
app.ShutdownMode = ShutdownMode.OnExplicitShutdown;
app.Run();
}));
appthread.SetApartmentState(ApartmentState.STA);
appthread.Start();
while (true)
{
var key =Console.ReadKey().Key;
// Press 1 to create a window
if (key == ConsoleKey.D1)
{
// Use of dispatcher necessary as this is a cross-thread operation
DispatchToApp(() => new Window().Show());
}
// Press 2 to exit
if (key == ConsoleKey.D2)
{
DispatchToApp(() => app.Shutdown());
break;
}
}
}
static void DispatchToApp(Action action)
{
app.Dispatcher.Invoke(action);
}
}
Also if you want to re-open the very same window make sure it is never closed completely, to do that you can handle the Closing event and cancel it using e.Cancel = true;, then just call Hide on the window to "close" it and Show to "open" it again later.
When you add window as a parameter to app.Run you link the lifetime of your app to your window. Don't do that:
private static void OpenWindow()
{
//Exception(Cannot create more than one System.Windows.Application instance in the same AppDomain.)
//is thrown at the second iteration.
var app = new System.Windows.Application();
var window = new System.Windows.Window();
app.Run();
window.Show();
//User closes the opened window manually.
}
I've not had chance to test this myself, but after reading up on your error, I found some information. Basically, it sounds like the AppDomain you are running in can only be used once per application - so perhaps you need to create a new AppDomain each time you want to re-create the application. See here for some more information on this.
Alternately, you could use System.Diagnostics.Process.Start(...) in order to fire off the application properly. Refer here for the documentation for the Process class.
Finally, if you are just wanting to allow the user to run the application from the command line, it might be simpler to write a command script and execute that from the command line.

Categories

Resources