Control Form from other Classes and other main Problems - c#

I'm not that good in OOP or even C# but I want to try to keep my code as clean as possible.
Lets say we've got something like that within the Namespace "GoogleCalendarNotificator":
public partial class MainForm : Form
{
private object calendarData;
public MainForm()
{
InitializeComponent();
}
private void recieveCalendarDataButton_Click(object sender, EventArgs e)
{
getCalendarDataBW.RunWorkerAsync();
}
private void getCalendarDataBW_DoWork(object sender, DoWorkEventArgs e)
{
try {
getCalendarData getCalendarDataObj = new getCalendarData();
calendarData = getCalendarDataObj.getData();
} catch (Exception err) {
statusHandler("Login Failed, Please check your Data", err.Message);
}
try {
workWithCalendarData workWithCalendarDataObj = new workWithCalendarData();
workWithCalendarDataObj.workWithData(calendarData, MainForm.ActiveForm);
statusHandler("New calendardata recieved");
} catch (Exception err) {
statusHandler("Login Failed, Please check your Data", err.Message);
}
}
public void statusHandler(string displayMessage, string tooltipMessage = null)
{
string curTime = DateTime.Now.Hour.ToString() + ":" + DateTime.Now.Minute.ToString();
statusLabel.Text = curTime + " - " + displayMessage;
if (tooltipMessage != null)
{
statusLabel.ToolTipText = "Original error message: " + tooltipMessage;
}
}
Is this a good solution for ErrorHandling?
And how about this part:
workWithCalendarData workWithCalendarDataObj = new workWithCalendarData();
workWithCalendarDataObj.workWithData(calendarData, MainForm.ActiveForm);
I simply want to give another class (workWithCalendarData) the possibility to interact with the MainForm. But I do not want simply written in the workWithCalendarData class something like:
MainForm hehe = new MainForm();
hehe.DOSOMETHING();
I want it to be dynamicly if anybody knows what I mean. Like give the class the Information needed to work with the Form (a.e. MainForm.ActiveForm).

MainForm hehe = new MainForm();
hehe.DOSOMETHING();
Well, that just doesn't work. It creates a new form, one that isn't visible because Show() wasn't called. You'll need a reference to the existing form, this in the MainForm's code. You can pass it to the worker class by calling its constructor, passing the reference.
That is however a Bad Idea. It makes your worker class dependent on the user interface. Changing the GUI, happens often because it is, well, so visible, will break your worker class. You solve that problem by using events. Let the worker class raise the event when something worthwhile happens. So that the form can then obtain the information from the class object and update the UI accordingly.
Also look into the MVC pattern to get some ideas.

Remember that your form is also a class. Use standard OOP mechanisms for allowing one class to interact with another. Events, Properties, and Methods can all be used.

Related

Updating Toolstripstatuslabel in Thread of closing form

I have a Order form. Once a order is complete, I use a thread to email the order to the supplier. The Thread is use to prevent the system hanging while the order is exported to pdf and sent.
The Problem: I would like to place an message on the MDIParent Toolstripstatuslabel once the threat completes without error to confirm the order was sent. But I get an error: "System.NullReferenceException: Object reference not set to an instance of an object". Which I could be wrong, refers to the Child windows disposed the toolstripstatuslabel reference on the parent form when it closed, so the threat cant access it anymore. I know the easy solution would be to use a MessageBox to confirm all went good and well...but why make it easy if you can do it elegant?
So my question: How can I reference a control in the parent form from the threat? I tried looking at invoke, but not sure how to implement it or if it is actually the correct direction.
EDIT:
My code from the childform
public partial class frm_n_order : Form
{
.
.
private void bProcess_Click(object sender, EventArgs e)
{
.
.
.
new Thread(new ThreadStart(delegate
{
fExportOrder(strOrderNo);
fSendMailv2(strPlant, strSupCode, strOrderNo);
})).Start();
this.close();
}
private void fExportOrder(string strOrderNo)
{
//export order to pdf
}
private void fSendMailv2(string strPlant, string strSupCode, string strOrderNo);
{
// get pdf
// get email address
try
{
// send email
((MDIParent1)MdiParent).tsslMain.Text = "Order No:" + strOrderNo + " was successfully send to " + strEmails; //here I need to find a different way of accessing the Toolstripstatuslabel in the parent form
}
catch
{
MessageBox.Show("Email did not send");
}
}
}
EDIT:
Ok, so after spending more than a day trying to figure out how to use Invoke, I realize while it seems like good practice when working with threads, its not my answer. My problem is directly related to the childform closing disposing all the controls so it looses its reference to the MdiParent. To solve the problem I did the following:
In my child class I added:
public static Form IsFormAlreadyOpen(Type FormType)
{
foreach (Form OpenForm in Application.OpenForms)
{
if (OpenForm.GetType() == FormType)
return OpenForm;
}
return null;
}
I dont think it is the most elegant solution but the theory is that my Parent form will always be open when I need to access the Toolstripstatuslabel. So I basically loop through all the open forms to find the reference to the active MdiParent instance which then gets passed back to the caller. In the thread I then use the following code.
MDIParent1 fm = null;
if ((fm = (MDIParent1)IsFormAlreadyOpen(typeof(MDIParent1))) != null)
{
fm.Toolstripstatuslabel1.Text = "Order No:" + strOrderNo + " was successfully send to " + strEmails;
}
I'm still looking for a better approach, but for now this works.
Ok, so after spending more than a day trying to figure out how to use Invoke, I realize while it seems like good practice when working with threads, its not my answer. My problem is directly related to the childform closing disposing all the controls so it looses its reference to the MdiParent. To solve the problem I did the following:
In my child class I added:
public static Form IsFormAlreadyOpen(Type FormType)
{
foreach (Form OpenForm in Application.OpenForms)
{
if (OpenForm.GetType() == FormType)
return OpenForm;
}
return null;
}
I dont think it is the most elegant solution but the theory is that my Parent form will always be open when I need to access the Toolstripstatuslabel. So I basically loop through all the open forms to find the reference to the active MdiParent instance which then gets passed back to the caller. In the thread I then use the following code.
MDIParent1 fm = null;
if ((fm = (MDIParent1)IsFormAlreadyOpen(typeof(MDIParent1))) != null)
{
fm.Toolstripstatuslabel1.Text = "Order No:" + strOrderNo + " was successfully send to " + strEmails;
}
I'm still looking for a better approach, but for now this works.
It's hard for me to overlook someone saying "but why make it easy if you can do it elegant?"
Awesome!
I figure if we can do something elegantly, then in the future it should be easy.... right?
Anyways, hoping you find the below helpful.
A note: It looked to me like you were declaring your thread as a local variable and not storing it outside the local scope. If we want something to live past the end of the scope, it's a good idea to store a reference to it (which is done using a private Task field in the below example).
Sure, the thread would get added to the threadpool and stored somewhere in the framework even if it's just a local variable, so I think it wouldn't abort due to garbage collection as you have it, but I don't like the idea of instances floating around that I don't have references to.
public class MyChildForm : Form
{
private Task longRunningTask;
private Task closeTask;
public string ResultOfTimeConsumingOperation { get; private set; }
protected override Dispose(bool disposing)
{
if (disposing)
{
longRunningTask?.Dispose();
closeTask?.Dispose();
}
base.Dispose(disposing);
}
private void TimeConsumingOperation1()
{
Thread.Sleep(TimeSpan.FromSeconds(8));
ResultOfTimeConsumingOperation = "Hooray we finished the work lol";
this.closeTask =
Task.Factory.FromAsync(
BeginInvoke(new Action(Close)),
EndInvoke);
}
protected override void OnLoad()
{
base.OnLoad();
this.longRunningTask =
Task.Run(TimeConsumingOperation1);
}
}
public class MyParentForm : Form
{
private List<Form> childForms;
public MyParentForm() : base()
{
childForms = new List<Form>();
}
protected override void OnLoad()
{
base.OnLoad();
RunChildForm();
}
private void RunChildForm()
{
var childForm = new MyChildForm();
childForms = childForms.Append(childForm).ToList();
childForm.FormClosing += ChidlForm_FormClosing;
childForm.Show();
}
private void ChildForm_FormClosing(object sender, FormClosingEventArgs e)
{
var childForm = sender as MyChildForm;
childForm.FormClosing -= ChildForm_FormClosing;
if (childForms.Contains(childForm))
childForms =
childForms.
Except(new Form[] { childForm }).
ToList();
// tada
myStatusLabel.Text = childForm.ResultOfLongRunningProcess;
}
// main window is closing
protected override void OnFormClosing(FormClosingEventArgs e)
{
// let's close any windows we left open
var localForms = childForms.ToList();
childForms = new List<Form>();
foreach (var form in localForms)
form.Close();
}
}

how do i call a method from a usecontrol to a another usercontrol?

I have a usercontrol where in I add/update data and save it to a database and i want the datagrid to refresh right a way using my method refreshDVG1();
public void refreshDVG1()
{
try
{
dataGridView1.CurrentCell.Selected = this.dataGridView1[0, 0].Selected;
datset.Clear();
sda.Fill(datset);
dataGridView1.Refresh();
if (dataGridView1.RowCount < 1)
{
datset.Clear();
string row = "NO items found";
datset.Rows.Add(row);
}
}
catch(Exception ex)
{
MessageBox.Show("" + ex);
}
}`
but it doesn't seems to be working and tried using the method on a button on the same usercontrol of the datagridview and it works fine so I dont know why I get an error btw the error I receive was I was receiving a nullrefernce object or something..I'm new to c# so I kind off mess up this one I hope you help me in this problem
code for update and please note that this is from he different usercontrol and both two usercontrol are on the same form
<br><i>private void UpdateAcc_Click(object sender, EventArgs e)
{
SuspendLayout();
using (MySqlConnection conn = new MySqlConnection(myConnection))
{
string query = "UPDATE `deqor`.`users` SET `first_name`=?name, `middle_name`=?mname, `last_name`=?lname WHERE `userid`=?para;";
conn.Open();
using (MySqlCommand cmd = new MySqlCommand(query, conn))
{
try
{
cmd.Parameters.AddWithValue("?name", Fname.Text);
cmd.Parameters.AddWithValue("?mname", Mname.Text);
cmd.Parameters.AddWithValue("?lname", Lname.Text);
cmd.Parameters.AddWithValue("?para", manageACC.staticNumData);
cmd.ExecuteNonQuery();
MessageBox.Show("success");
//MainForm main = Form.ActiveForm as MainForm;
manageACC main1 = this.Parent.Parent.Parent.Parent as manageACC;
main1.refreshDVG1();
}
catch (Exception ex)
{
MessageBox.Show("error" + ex);
}
}
conn.Close();
}
ResumeLayout();
}
There are different ways to achieve this approach, one of them is you can create Event on second usercontrol and raise it when click on button, then in form container handle that event and in handler call the first UserControl method.
The another way you can pass the first UserControl in second one and call the method directly.
You can find another solution in this place
It depends on your code, archticture and project structure. Can not offer a answer fr your question.
If you want to find the best solution, you can add more details.
public partial class edit : UserControl
{
public EventHandler DataUpdated;
}
private void UpdateAcc_Click(object sender, EventArgs e)
{
// Saving Data In DB
//MainForm main = Form.ActiveForm as MainForm;
//manageACC main1 = this.Parent.Parent.Parent.Parent as manageACC;
//main1.refreshDVG1();
//Instead of commented code raise the event
if(DataUpdated != null)
DataUpdated(this, System.eventArgs.Empty);
}
Then in main form code behind handle the DataUpdated event:
//edit1 imagine is id of second usercontrol instance
edit1.DataUpdated += (s,e) =>
{
//you have usercontrol1 instance here, so just call method directly here
//manageACC1imagine is id of first usercontrol instance
manageACC1.refreshDVG1();
}

C# Take combobox item from one form and add its name as text to another

Ok so I'm attempting to create a simple game. In a nutshell it's a resource management game where the player will attempt to manage a thieves guild. In regards to running missions I've created a Thief class, a new instance of which is created when a new thief is recruited. I have coded within the thief class the ability to gain experience and level up.
Here's my specific problem:
I want the player to be able to select which thief/thieves to send on a mission. I have thought about it and figured that opening a new form and populating it with checkboxes is the easiest way to allow this. These checkboxes will be related to a List<thief> of thieves, the player then checks the thieves s/he wants to send and these are then stored in another List<thief> and passed on to the run mission function.
I've built a separate project with the intention of testing and playing around with this before putting it into the main program. The test project consists of two forms: The first (frmMain) with a textbox to hold the selected options and a button to open the second form (frmSelect). Currently I can open and populate the second form (frmSelect) but when I try to add the checked options to the textbox I simply...well can't.
So far I have tried directly accessing the textbox by typing frmMain.txtOptionsDisplay in the cs file of frmSelect but it causes the following error:
An object reference is required for the non-static field, method or
property
I tried to create a new form in frmSelect and make it equal to the active instance of frmMain with: Form frmTemp = frmMain.ActiveForm; and then alter the textbox using frmTemp as a go-between but that produced the error:
'System.Windows.Forms.Form' does not contain a definition for
'txtOptionsDisplay'.
Having searched both google and stackoverflow forums I've encountered answers that I either have never heard of (Threading) or answers that I kind've recognise but can't interpret the code pasted to make it relevant to my problem (delegates).
Any advice or pointers would be fantastic.
EDIT:
frmMain code:
public frmMain()
{
InitializeComponent();
selections.Add("Option 1");
selections.Add("Option 2");
}
private void btnClick_Click(object sender, EventArgs e)
{
frmSelectOptions.Show();
int length = selections.Count();
for (int i = 0; i < length; i++)
{
CheckBox box = new CheckBox();
box.Text = selections[i];
box.AutoSize = true;
box.Location = new Point(50, 50*(i+1));
frmSelectOptions.grpControls.Controls.Add(box);
}
}
public void updateText(string option)
{
txtOptionsDisplay.Text += option;
}
}
frmSelect code:
public List<CheckBox> selectedOptions = new List<CheckBox>();
Form frmTemp = frmMain.ActiveForm;
public frmSelect()
{
InitializeComponent();
}
private void btnSelect_Click(object sender, EventArgs e)
{
foreach (CheckBox box in grpControls.Controls)
{
if (box.Checked == true)
selectedOptions.Add(box);
}
this.Hide();
}
}
I hope this formats correctly... I'm kinda new and don't know how to indent. Oh look there's a preview...
Does this help?
Your problem is that controls defined within a form by default receive the private access identifier. Hence you could just add a property along the lines of
public ControlType ProxyProperty {
get {
return txtOptionsDisplay;
}
}
Besides from that you should think about wether what you're trying is actually a good solution. Manipulating forms from one to another will become a huge clusterfuck in terms of maintenance later on.
I'd suggest using the Singleton pattern for your frmMain. This will help safeguard you from accidentally launching another instance of frmMain and at the same time, will give you access to frmMain's objects. From there, you can either write accessors to Get your txtOptionsDisplay or you can make it public. Below is an example:
public class frmMain
{
private static frmMain Instance = null;
private static object LockObj = new object();
public static frmMain GetMain()
{
// Thread-safe singleton
lock(LockObj)
{
if(Instance == null)
Instance = new frmMain();
return Instance;
}
}
public string GetOptionsDisplayText()
{
return txtOptionsDisplay.Text;
}
}
public class frmSelect
{
private void frmSelect_Load(object sender, EventArgs e)
{
// Set whatever text you want to frmMain's txtOptionsDisplay text
txtDisplay.Text = frmMain.GetMain().GetOptionsDisplayText();
}
}
If you do go this route, don't forget to update Program.cs to use frmMain's singleton.
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Application.Run(new frmMain()); - Old method
Application.Run(frmMain.GetMain());
}

Multithreading to speed up load times

I made a program that loads a bunch of computer information. In the Form_Load event I have it initialize 3 (that number will grow) panels of information. One that has a bunch of unit information seems to make the program load rather slowly. I've tried to speed it up a bunch by switching from WMI to using Native calls, which helped a bunch. Soon though I'm going to have network information posted as well. I used to load that panel but i disabled it for a little bit till I work out the bugs in my other panels. So while learning how I can use a seperate thread to update my battery information I figured that I might be able to create seperate threads in my unit information panel so that it might could load faster. I dont know that any of my information would cause concurrent issues, but i can work on that.
I want to start small so what if i change this
private void Form1_Load(object sender, EventArgs e)
{
unitInformationPanel1.PopulateUnitInformation();
batteryInformationPanel1.InitializeBatteries();
magStripeReaderPanel1.SetupPointOfSale();
}
to this
private void Form1_Load(object sender, EventArgs e)
{
Thread infoThread = new Thread(new ThreadStart(unitInformationPanel1.PopulateUnitInformation));
infoThread.Start();
batteryInformationPanel1.InitializeBatteries();
magStripeReaderPanel1.SetupPointOfSale();
}
would the info thread be terminated when populate unit info is done? or would it be better to move that thread creation into PopulateUnitInformation? here is what it looks like.
public void PopulateUnitInformation()
{
unitModelLabel.Text = Properties.Settings.Default.UnitModelString;
serialNumberLabel.Text = Properties.Settings.Default.UnitSerialString;
biosVersionLabel.Text = UnitBios.GetBiosNumber();
osLabel.Text = OS.getOSString();
cpuLabel.Text = UnitCpu.GetCpuInfo();
var hdd = HddInfo.GetHddInfo();
diskNameLabel.Text = hdd.Name;
diskCapacityLabel.Text = hdd.Capacity;
diskFirmwareLabel.Text = hdd.Firmware;
memoryLabel.Text = MemoryInformation.GetTotalMemory();
NetworkPresenceInformation.GetAdapatersPresent();
biometricLabel.Text = BiometricInformation.IsPresent ? "Present" : "Not Present";
var networkAdaptersPresense = NetworkPresenceInformation.GetAdapatersPresent();
bluetoothLabel.Text = networkAdaptersPresense[0] ? "Present" : "Not Present";
wifiLabel.Text = networkAdaptersPresense[1] ? "Present" : "Not Present";
cellularLabel.Text = networkAdaptersPresense[2] ? "Present" : "Not Present";
}
--
wow i just ran it with the infothread and it still took some time to load (might be the 12 panels i created in the main thread. but it loaded the 12 frames and the unit information panel populated its information after everything loaded. That was cool, but is it safe? is it somewhat easy to make 12 threads for my panels? or is that dumb?
EDIT
this is what i did for stopwatch.
Stopwatch programTimer;
public Form1()
{
programTimer = Stopwatch.StartNew();
InitializeComponent();
SetupDebugWindow();
TerminateKeymon();
UnitModel.SetModel();
UnitSerialNumber.SetSerialNumber();
}
private void Form1_Shown(object sender, EventArgs e)
{
audioBrightnessPanel1.UpdateBrightnessTrackbar();
applicationLauncherPanel1.LoadApplications();
programTimer.Stop();
Console.WriteLine("Load Time: {0}",programTimer.ElapsedMilliseconds);
timer1.Start();
}
Will this be accurate?
EDIT 2 6/18/2012
Well I took the advice of using backgroundworker. Please let me know if i did this right.
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
void BackgroundWorker1DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
unitInformationPanel1.PopulateUnitInformation();
batteryInformationPanel1.InitializeBatteries();
magStripeReaderPanel1.SetupPointOfSale();
}
You've asked a very broad question, but I'm going to give some general advice. If you want more specific information, you should consider deleting this question and posting more specific individual questions.
First and foremost, you should very strongly consider using something like the System.Threading.Task class for your multithreaded operations. There is a ton of information online about how to get started with it and how you can use Tasks to manage asynchronous operations. The short story is that if you're spinning up your own thread (as you're doing above), you almost certainly should be using something else to do that for you.
Adding multithreading to your code will not, in the strictest sense of the word, make it any "faster"; they will always take the same amount of total processor time. What it can and will do is two things: free up the UI thread to be responsive and allow you to split that "total processor time" across multiple cores or processors, should those be available to the system. So, if you have operation X that takes 10 seconds to complete, then just shifting operation X to another thread will not make it complete any faster than 10 seconds.
No, what you are doing above is not safe. I'm assuming that somewhere you've turned off checking for cross-thread communication errors in your app? Otherwise, that code should throw an exception, assuming this is a WinForms or WPF application. This is one reason to use Tasks, as you can easily separate the part of your process that actually takes a long time (or isn't UI related), then add a task continuation that uses the results and populates the UI elements within a properly synchronized context.
So my final approach this was as follows. I felt that my Main Form was doing more than it should. Sticking with the single responsibility principle I decided that MainForm should only be responsible for one thing, showing and displaying all 12 panels (now down to 11, i turned one into a menu item). So moved all the multithreading out of mainform and into program.cs. I found that this was even a little more difficult. What I did find though was a simple solution that allows me to not even worry about multithreading at all. It was the Idle event. Here is what i chose to do.
[STAThread]
static void Main()
{
DateTime current = DateTime.Now;
DateTime today = new DateTime(2012,7,19);
TimeSpan span = current.Subtract(today);
if (span.Days<0)
{
MessageBox.Show("Please adjust Time then restart Aspects","Adjust Time");
Process.Start("timedate.cpl").WaitForExit();
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Idle += new EventHandler(Application_Idle);
mainForm = new MainForm();
mainForm.Closing += new CancelEventHandler(mainForm_Closing);
#if !DEBUG
TerminateKeymon();
StartSerial();
SetupDefaultValues();
EmbeddedMessageBox(0);
#endif
Application.Run(mainForm);
}
}
static void Application_Idle(object sender, EventArgs e)
{
Application.Idle -= Application_Idle;
mainForm.toolStripProgressBar1.Increment(1);
UnitInformation.SetupUnitInformation();
mainForm.toolStripProgressBar1.Increment(1);
Aspects.Unit.HddInfo.GetHddInfo();
mainForm.toolStripProgressBar1.Increment(1);
for (int i = 0; i < mainForm.Controls.Count; i++)
{
if (mainForm.Controls[i] is AbstractSuperPanel)
{
try
{
var startMe = mainForm.Controls[i] as AbstractSuperPanel;
startMe.StartWorking();
mainForm.toolStripProgressBar1.Increment(1);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + mainForm.Controls[i].ToString());
}
}
}
mainForm.toolStripProgressBar1.Value = 0;
}
to sum up what that does is is I add a idle listener event. Once the thead goes idle (basically meaning that Mainform is finished drawing and making all 12 panels and is showing on my desktop) I then kill the idle event listener and tell all my panels and classes to start working one at a time, updating my progress bar as I go. It works great. The load time is still the same as it was before, but there is window visibile after only a few seconds. Maybe not the best use of resources, but i think the solution is simple and straight forward.
I had a question somewhat related to this for Mobile app development a few months back (see How to write a Trigger?), and Marc "the man" Gravell posted back with a simple class that I modified to return data to my main application whenever the thread was complete.
The actual class I put into use has loads of pointless data (for you), so I'm going to paste in a revised version of Mr. Gravell's code using techniques which I used to make them work:
First, I had to create my own EventArgs class:
public class SuperEventArgs : EventArgs {
private object data;
public SuperEventArgs(object data) : base() {
this.data = data;
}
public object Data { get { return data; } }
}
Using that, here is a class I created to pass my data back to the main thread:
public delegate event DataChangedHandler(object sender, SuperEventArgs e);
public class Simple1 {
private object parameter1, parameter2;
private Control parent;
#if PocketPC
public delegate void MethodInvoker(); // include this if it is not defined
#endif
public Simple1(Control frmControl, object param1, object param2) {
parent = frmControl;
parameter1 = param1;
parameter2 = param2;
}
public event DataChangedHandler DataChanged;
public void Start() {
object myData = new object(); // whatever this is. DataTable?
try {
// long routine code goes here
} finally {
if (DataChanged != null) {
SuperEventArgs e = new SuperEventArgs(myData);
MethodInvoker methInvoker = delegate {
DataChanged(this, e);
};
try {
parent.BeginInvoke(methInvoker);
} catch (Exception err) {
Log(err); // something you'd write
}
}
}
}
}
Back in the actual main thread of execution, you'd do something like this:
public partial class Form1 : Form {
private Simple1 simple;
public Form1() {
object query = new object(); // something you want to pass in
simple = new Simple1(this, query, DateTime.Now);
simple.DataChanged += new DataChangedHandler(simple1_DataChanged);
Thread thread = new Thread(simpleStart);
thread.Start();
}
private void simpleStart() {
if (simple != null) {
simple.Start();
}
}
private void simple1_DataChanged(object sender, SuperEventArgs e) {
MyFancyData fancy = e.Data as MyFancyData;
if (fancy != null) {
// populate your form with the data you received.
}
}
}
I know it looks long, but it works really well!
This is not anything I have actually tested, of course, because there isn't any data. If you get to working with it and you experience any issues, let me know and I'll happily help you work through them.
~JoeP

how do I pass a reference to an object via button_click in WPF/C#

I have two pages in WPF. Page A contains all of my code. Page B is meant to be like a control panel where I click buttons to operate window A.
The problem I am running into is I want to make function calls from B to A but I am getting a scope error.
In the below code I am getting the error specifically on the axFlash object.
namespace GoogleMapsFlashInWpf
{
public partial class ButtonPage : Page
{
public ButtonPage()
{
InitializeComponent();
}
private void ClearMarkersButton(object sender, RoutedEventArgs e)
{
StackTrace asdf = new StackTrace();
Console.WriteLine(asdf.GetFrame(0).GetMethod().Name.ToString() + " called from " + asdf.GetFrame(1).GetMethod().Name.ToString());
XElement call = new XElement("invoke",
new XAttribute("name", "clearMarkers"),
new XAttribute("returntype", "xml"));
try
{
axFlash.CallFunction(call.ToString(SaveOptions.DisableFormatting));
}
catch (Exception error)
{
Console.WriteLine(error.ToString());
}
}//end ClearMarkersButton
}
}
The error is right...the axFlash object doesn't exist in the scope of that method. You need to make axFlash an object defined under ButtonPage class. Then, you must make sure that axFlash object is set before you wish to call that function.

Categories