I'm running a main WinForm with most UI elements, and then an Add form is called when the Add button is picked. It should receive input, and send it back to the WinForm once accepted.
This code runs when you click the "Add" button on the main class:
public void addButton_Click(object sender, EventArgs e)
{
AddView newadd = new AddView();
newadd.Show();
}
This code (also in the main class) should run based upon a button in the AddView:
public void AddDashObject(string dashName, string dashIdentifier, int dashFunction, string dashFunctionInfo, int dashVerbosity)
{
DashObject tmp = new DashObject("","",0,"",0);
tmp.DashName = dashName;
tmp.DashIdentifier = dashIdentifier;
tmp.DashFunction = dashFunction;
tmp.DashFunctionInfo = dashFunctionInfo;
tmp.DashVerbosity = dashVerbosity;
dashloaded.Add(tmp);
ReloadDashObjects();
}
I'm not really sure how to communicate between the forms - I can use a type created in the main class, and also methods, but I'm pretty sure I'm creating a separate instance. How can I communicate with the existing one?
MainView mnfrm = new MainView();
MainView.DashObject tmp = new MainView.DashObject("","",0,"",1); // Defaults
private void button1_Click(object sender, EventArgs e)
{
mnfrm.dashloaded.Add(tmp); // Add the default DashObject to MainView's currently loaded DashObjects
mnfrm.ReloadDashObjects(); // Reload the list
}
Not sure how to proceed on this - any advice?
Since the Add dialog is expected to be modal, the decoupled way to do this is to only close the dialog with an OK status. I.e. the form is just an input control that doesn't actually "do" anything.
Then the main form can:
1) check how the dialog was closed right after ShowDialog(),
2) call some GetResult() function to get the values from the add form before disposing it.
3) call the business logic that actually creates and reloads the DashObjects.
Related
I am new to WPF and Coding in general, I am trying to create a small UI to read and write data on .txt files. All the reading part functions works well but now I am having trouble making a small UI to display the information found in the .txt files.
My problem is more with how button clicks work in WPF. All the data is stored in the forms of object of class Static_Data_Scheme and Dynamic_Data_Scheme inside the program, these class are just simple collection of Dictionaries Objects. Part of my data is 'static' meaning it will be stored in .txt files that won't change location and so can be loaded when the program is started, and another part of my data is 'Dynamic' meaning it can be stored anywhere and the file path can be changed using a file explorer in the program. Important thing to note, the Static_Data_Scheme is needed to generate the Dynamic_Data_Scheme.
My initial way of handling it when I made the program to test it out was to generates both Data Scheme with the same button press called load, but since the static dictionaries can be loaded right at the start of the program I want to try and add that method to the MainWindow instead and only have the program generates the Dynamic_Data_Scheme when I press the load button, but I'm unable to find any documentation on how to add arguments to the click method of the button.
Current code that works but that I don't like due to the fact that Static_Data_Scheme.Start method is called each time the load button is pressed and could instead be loaded only once when the program starts :
public MainWindow()
{
InitializeComponent();
}
private void Save_Loader_Click(object sender, RoutedEventArgs e)
{
Static_Data_Scheme static_Data_Scheme = new Static_Data_Scheme();
static_Data_Scheme = static_Data_Scheme.Start();
Dynamic_Data_Scheme dynamic_Data_Scheme = new Dynamic_Data_Scheme();
Save_Parser.Parse_Save(#"file_path", static_Data_Scheme, ref dynamic_Data_Scheme);
}
What I wanna try to achieve is something like that :
public MainWindow()
{
InitializeComponent();
Static_Data_Scheme static_Data_Scheme = new Static_Data_Scheme();
static_Data_Scheme = static_Data_Scheme.Start();
}
private void Save_Loader_Click(object sender, RoutedEventArgs e)
{
Dynamic_Data_Scheme dynamic_Data_Scheme = new Dynamic_Data_Scheme();
Save_Parser.Parse_Save(#"file_path", static_Data_Scheme, ref dynamic_Data_Scheme);
}
But this doesn't work due to the fact that the Save_Parser.Parse_Save method lack the static_Data_Scheme variable and I can't add it to the Save_Loader_Click method either.
So my question is how do I tell my ave_Loader_Click method to get the static_Data_Scheme from the program?
You almost had it, just move the variable outside of your method:
Static_Data_Scheme static_Data_Scheme = new();
public MainWindow()
{
InitializeComponent();
/* static_Data_Scheme = ???? */static_Data_Scheme.Start();
}
private void Save_Loader_Click(object sender, RoutedEventArgs e)
{
var Data_Scheme = new Dynamic_Data_Scheme();
Save_Parser.Parse_Save(#"file_path", static_Data_Scheme, ref dynamic_Data_Scheme);
}
I've read several questions/answers related to this problem but couldn't find a solution applicable to problem.
I have a form (MainForm) and a button (Upload) on it. When I click on the button (after selecting a file from a ComboBox to be uploaded to the server), it opens another form (UploadBackupForm) and uploads a file to the server. The upload process is controlled in UploadBackupForm and the form looks like this:
This works as long as upload is done once, I mean, the UploadBackupForm is called one time. The second time I click on the Upload button, UploadBackupForm opens and (after uploading some data) it throws an error saying:
System.InvalidOperationException: 'Invoke or BeginInvoke cannot be called on a control until the window handle has been created.'
at this specific line(s):
DurationLabel.Invoke((MethodInvoker)delegate
{
DurationLabel.Text = Count2Duration(count);
});
This has puzzled me because it works when it's done once, and doesn't work at the second time. I have basic knowdledge in C#, so I don't know what's causing this and how to solve it.
MainForm:
private void Upload2ServerButton_OnClick(object sender, EventArgs e)
{
Form UBF = new UploadBackupForm();
UBF.ShowDialog();
}
UploadBackupForm:
public partial class UploadBackupForm : Form
{
public UploadBackupForm()
{
InitializeComponent();
}
public static System.Timers.Timer timer = new System.Timers.Timer();
public static int count = 0;
private void UploadBackup_Load(object sender, EventArgs e)
{
timer.Interval = 1000;
timer.Elapsed += new ElapsedEventHandler(delegate {
count++;
// didn't do any good (this.IsHandleCreated or DurationLabel.IsHandleCreated)
// if (!this.IsHandleCreated)
// {
// this.CreateControl();
// }
DurationLabel.Invoke((MethodInvoker)delegate
{
DurationLabel.Text = Count2Duration(count);
});
});
// upload the archive to the server
new Thread((ThreadStart)delegate
{
FTP.Item[] items = FTP.ListDirectoryDetails(DataIO.FTP.Server, DataIO.FTP.Username, DataIO.FTP.Password, DataIO.FTP.UploadDir);
// here, I upload the file to the server and update the progress bar and the uploaded / total labels
Because the timer variable is static it remains even after the form is closed. It contains a reference to a delegate which holds a reference to the form so the previous instances are kept alive through the lifetime of your application. Also, the single timer posts callbacks to all previous instances along with the current one.
As correctly noted in the comments by Evk, make the timer and count non-static so they are dedicated to each instance of the form.
In my project on the WindowsForms, if I have a static instance inside the form, when I'm opening my form at the first time, it works. But if I'll close it and open again, the form will be empty. Why can it be?
public partial class Computer : Form
{
static Indicators indicators = new Code.Indicators();
}
P.S. I'm making it static, because I want to save it's value after the form will be closed.
Edit 1: Opening the form
private void button3_Click(object sender, EventArgs e)
{
Computer computer = new Computer();
computer.ShowDialog();
}
Edit 2: Computer Form
namespace WF
{
public partial class Computer : Form
{
static Code.Indicators indicators = new Code.Indicators();
public Computer()
{
if (indicators.isComputerAlreadyRunning == false)
{
InitializeComponent();
pictureBox1.Image = Properties.Resources.Computer1;
indicators.isComputerAlreadyRunning = true;
}
}
// My not successful try to save the value of the variable
public Code.Indicators ShowForm()
{
return new Code.Indicators(indicators.isComputerAlreadyRunning);
}
}
}
I don't think that static members work well with the Windows Form lifecycle.
I suggest you make Indicators a normal instance member of your form. To preserve state beyond the life of a form you can copy your state from the form and copy it back to the form when you open it.
// Keep this in the proper place
var indicators = new Code.Indicators();
...
// Copy back and forth for the life time of the form
using (var form = new Computer())
{
form.Indicators.AddRange(indicators);
form.Close += (s, e) =>
{
indicators.Clear();
indicators.AddRange(form.Indicators);
}
}
...
According to the constructor in the Computer class, the indicators.isComputerAlreadyRunning is set to true the first time the form is created.
So when Computer is created the second time, the if condition will fail and the whole if block will be skipped. That means your InitializeComponent(); won't get run and hence nothing in the form will shows up.
Put the InitializeComponent(); outside the if clause to make it work.
There is a MenuItem click event MainMenu_Define_Material which opens a window called Material. I get info from a textbox called txt_density and I save that info in density and return to main window via OK-button having click event Material_btn_OK_Click.
My question is, how I can avoid passing the last session values every time I open the window Material?
I want, once density is set, every time I open Material window I want to see the values of previous session.
private void MainMenu_Define_Material(object sender, RoutedEventArgs e)
{
newWin_material = new Material();
newWin_material.btn_OK.Click += new RoutedEventHandler(Material_btn_OK_Click);
if (density != -1)
{
newWin_material.txt_density.Text = density.ToString();
}
newWin_material.ShowDialog();
}
private void Material_btn_OK_Click(object sender, RoutedEventArgs e)
{
density = System.Convert.ToSingle(newWin_material.txt_density.Text);
newWin_material.Close();
}
Not very clear where that density comes from, but you can insert that field in uour data class what you can hold on data layer or may be like ObjectDataProvider for modelview.
There are a lor of different solutioms our there. The basic idea is:
Define common, shared data storage and keep there alll values you want to share between different windows.
Define a data class. I used here a static class with a static member Desnity.
public static class DataClass
{
public static double Desnsity;
}
After in any window you're able to access that field (read/write), like
DataClass.Density
Hope this is clear.
There is no concept of Session in WPF. You can try creating a static variable to do this or a app config value or pass a parameter via the constructor.
If you are going to new it ( e.g. new Material(); ) then it is going to start with zero information. That is what new does. What is wrong with passing the value in the ctor?
Try
MainWindow
{
private newWin_material = new Material(); // just new it ONCE
// this may need to be in MainWindow ctor.
newWin_material.btn_OK.Click += new RoutedEventHandler(Material_btn_OK_Click);
I have an application that uploads files to a server, but when I press upload it freezes until it is done, so I was thinking to make another form pop up that says uploading and does all of the uploading on that form nested of freezing that main form. But to do this I need to be able to send the selected information to that other form.
I have tried using a BackgroundWorker but that doesn't work, the form still freezes.
The reason why its freezing is because you are doing uploading on the same thread as the GUI or main thread.
You could create a worker thread to handle the working of the uploading so the GUI doesn't lock while processing the upload.
Example:
private void uploadButton_Click(object sender, EventArgs e)
{
object[] params = new object[] { "your file what ever type this is a generic example"};
Thread uploadThread = new Thread(new ParameterizedThreadStart(processUpload));
uploadThread.IsBackground = true;
uploadThread.Start(params);
}
private void processUpload(object params){
// do upload logic here
object[] _params = (object[])params;
string s = _params[0].ToString();
}
Passing information from one form to another is straight forward, but this form will also result in a lock while processing. If that's what you want to do then just create a constructor to take a param for whatever you'd like to pass. Then call it accordingly.
private string something = null;
public MySecondForm(string Something){
this.something = Something;
MessageBox.Show(this.something);
}
// Call this in the parent form
MySecondForm mySecondForm = new MySecondForm("hello world");
mySecondForm.Show();
If you are using WebClient class, you can use UploadFileAsync method. Also you can pass some information from one form to another as follows.
Form2
Add a simple constructor to Form2.
public Form2(string path) { // ... }
Form1
Form2 frm2 = new Form2("Path");
Take a look at this example on Code Project for some implementation tips.