Use of 'this' in an event - c#

I need to retrieve some property of an element that trigger the event in this context:
SoundEffect alarm;
public MainPage()
{
InitializeComponent();
Pad1.MouseLeftButtonUp += new MouseButtonEventHandler(makeasound);
Pad2.MouseLeftButtonUp += new MouseButtonEventHandler(makeasound);
Pad3.MouseLeftButtonUp += new MouseButtonEventHandler(makeasound);
}
Pad1,2 and 3 are the names of some Ellipse I have in my xaml. Now if I try to do this in the code executed by the event ( declared immediately after the sample code above):
private void makeasound(object sender, MouseButtonEventArgs e)
{
string text = this.Name;
textBlock1.Text = text;
}
The Text Block becomes empty, so I guess the Name of the triggering element never gets there.
Now, things get more messy if I'm trying to retrieve a custom property of the "pads" called "Son", declared with the dependency method , which is a string, like this:
private void makeasound(object sender, MouseButtonEventArgs e)
{
string text = this.Son;
textBlock1.Text = text;
}
VS reports error:
'PhoneApplication.MainPage' does not contain a definition for 'Son' and no extension method 'Son' accepting a first argument of type 'PhoneApplication.MainPage' could be found (are you missing a using directive or an assembly reference?)
Where Phoneapplication is the name of the app and the main namespace of the code behind.
As if it weren't simple enough, what I'm tryin to do is this:
The custom property is actually an INT. I know I declared the dependency right since VS let me compile. Each Pad has this custom property storing an int, and I need to retrieve it to access an array element. The function triggered is this:
private void makeasound(object sender, MouseButtonEventArgs e)
{
int x = this.Son;
var sons = new[] { "sons/firstsound.wav", "sons/secondsound.wav", "sons/thirdsound.wav" };
string target = sons[x];
StreamResourceInfo info = Application.GetResourceStream(
new Uri(target, UriKind.Relative));
alarm = SoundEffect.FromStream(info.Stream);
Microsoft.Xna.Framework.FrameworkDispatcher.Update();
alarm.Play();
}
So, I declare an array storing URI's for sounds that I'd like to play("son" means sound in french, I'm from Belgium). I then use the INT associated with the triggering element to access the URI of a sound, then I play this sound.
The reason I do this is because I'd like to let the user change the INT value for each pad and therefore choose what sound each pad plays. The fact that I seem to have no choice but to declare this array each time the function is called (otherwise it's not in context) is not very elegant but I guess I can live with that ( array will have 50-60 elements in it)
So, for those who read this far, my problem is to use a property of the triggering event, which seems to be harder when it's a custom property. I put the rest of the logic in case someone had advices.
I thank anyone who read this message and who could maybe help me sorting this out. I read online documentation and I have two good c# books, but I havent found a solution for me.
Have a nice day.
EDIT: Some others are willing to help so here is the declaration of the dependency property(Sorry Daniel, hadn't seen you commented my original post)
namespace MyNamespace
{
public static class MyClass
{
public static readonly DependencyProperty SonProperty = DependencyProperty.RegisterAttached("Son",
typeof(string), typeof(MyClass), new PropertyMetadata(null));
public static string GetSon(UIElement element)
{
if (element == null)
throw new ArgumentNullException("element");
return (string)element.GetValue(SonProperty);
}
public static void SetSon(UIElement element, string value)
{
if (element == null)
throw new ArgumentNullException("element");
element.SetValue(SonProperty, value);
}
}
Mynamespace is nested inside the main namespace.

this refers to the current instance of MainPage. Not to the pad that was clicked. That's the sender:
var pad = (Pad)sender;
var text = pad.Name;
textBlock1.Text = text;
Son is an attached property, not a normal one. You can get its value like this:
var pad = (Pad)sender;
var son = MyClass.GetSon(pad);
Please note that you have declared it as a string. Seeing how you want to use it, it seems to make more sense to declare it as an int.

this refers to the instance of the type in which the method is defined in, in this case, MainPage. If you want to get the instance of the type that triggered the event, that's what's in the sender parameter:
private void makeasound(object sender, MouseButtonEventArgs e)
{
textBlock1.Text = ((Pad)sender).Name;
}

Related

Unwanted member change because of reference

I am writing a piece of code but cannot figure out why it is showing some (from my point of view) weird behaviour. I get this is due to how I have written the code, but I cannot understand why it is not doing what I want it to do.
I have an eventhandler:
private void heatFinishedHandler(object sender, List<Kart> e)
{
mainForm.enableControls();
server.karts = e;
}
If I add e.Clear(); to it, it also clears server.karts.
The argument e comes from another class:
private List<Kart> kartlist = new List<Kart>();
heatFinished?.Invoke(this, kartlist);
The heatFinished event and the heatFinishedEventHandler are connected.
What do I need to do to get e by value, instead of reference? Or is it a value type, but is it pointing to kartlist?
I want to be able to get the value of e and store it in server.karts, not being able to change kartlist.
Make a copy of the list you pass to the function like
private List<Kart> kartlist = new List<Kart>();
heatFinished?.Invoke(this, kartlist.ToList());
Or do it inside the function like
private void heatFinishedHandler(object sender, List<Kart> e)
{
mainForm.enableControls();
server.karts = e.ToList();
}
.ToList() will make a new List-instance with the same values as the original one.

Passing a variable between forms WINFORMS [duplicate]

Wierd behaviour when passing values to and from second form.
ParameterForm pf = new ParameterForm(testString);
works
ParameterForm pf = new ParameterForm();
pf.testString="test";
doesn't (testString defined as public string)
maybe i'm missing something? Anyway I'd like to make 2nd variant work properly, as for now - it returns null object reference error.
Thanks for help.
Posting more code here:
calling
Button ParametersButton = new Button();
ParametersButton.Click += delegate
{
ParameterForm pf = new ParameterForm(doc.GetElementById(ParametersButton.Tag.ToString()));
pf.ShowDialog(this);
pf.test = "test";
pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit);
};
definition and use
public partial class ParameterForm : Form
{
public string test;
public XmlElement node;
public delegate void ParameterSubmitResult(object sender, XmlElement e);
public event ParameterSubmitResult Submit;
public void SubmitButton_Click(object sender, EventArgs e)
{
Submit(this,this.node);
Debug.WriteLine(test);
}
}
result:
Submit - null object reference
test - null object reference
pf.ShowDialog(this); is a blocking call, so pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit); is never reached: switch the order.
Submit(this,this.node); throws a null object reference because no event is assigned to it (see above). Generally, you should always check first: if (Submit != null) Submit(this,this.node);
You should change ``pf.ShowDialog(this);topf.Show(this);` so that your main form isn't disabled while your dialog box is open, if that's what you want, or use the model below (typical for dialog boxes.)
I'm not sure what pf_Submit is supposed to do, so this might not be the best way to go about it in your application, but it's how general "Proceed? Yes/No" questions work.
Button ParametersButton = new Button();
ParametersButton.Click += delegate
{
ParameterForm pf = new ParameterForm(testString);
pf.ShowDialog(this); // Blocks until user submits
// Do whatever pf_Submit did here.
};
public partial class ParameterForm : Form
{
public string test; // Generally, encapsulate these
public XmlElement node; // in properties
public void SubmitButton_Click(object sender, EventArgs e)
{
Debug.WriteLine(test);
this.Close(); // Returns from ShowDialog()
}
}
When you want to use your second variant, you have to use a getString()-Method, where you can put the e.g. "testString". The way you wrote it, "testString" should be a method (and got brackets).
EDIT (a bit more precise):
You could write:
pf.getString(testString);
, if "pf" is an instance of your own class, otherwise you had to look up, whether you can retrieve a String in this class.
the thing was in line order :)
pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit);
and
pf.Test = "test";
should have been set before
pf.ShowDialog(this);
my mistake thingking that parameter can be passed after 2nd form was displayed
thnx for answers

I cannot change the image in pictureBox1 from code in C#

First things first: Im pretty new to Programming, and I'm trying to learn the C# Language
My Goal: Having a method that changes the picture in pictureBox1.
Issue: I get the error that tells me that an object reference is required for non-static field.
Here's a snippet of my class where the method should go.
private class Execute
{
private void valueChecker(char value)
{
for (int i = 0; i <= charLenght; i++)
{
if (value != CharArray[i])
{
i++;
}
else if (value == CharArray[i])
{
CorrectLetter(value);
svalue = true;
}
}
if (svalue == true)
{
/* This is where the command is happening.
But I get error message : "An object reference is required for the non-static field, method or property."
*/
pictureBox1.Image = photos[x];
x++;
}
}
}
I have also tried making new classes and methods other places in the code, and call it from the if statement, but I don't get this to work.
I need to change the picture in pictureBox1 if the svalue == true
A little further info on what exactly Im doing:
Im making a hangman game as an exercise, and I want to update the Image in pictureBox1 if the input letter can't be found in the answer.
The pictures are stored in an array I have called photos[].
Your method declaration should be something like this:
public void valueChecker(char value,PictureBox pictureBox1)
var MyImage = new Bitmap(photos[x]);
pictureBox1.Image = (Image) MyImage ;
Your class needs a reference to the PictureBox. You can add a property and set it after creating an instance of the class or even pass it right into the constructor..
private class Execute
{
public PictureBox pBox {get; set;}
public Execute(PictureBox pb)
{
pBox = pb;
}
private void valueChecker(char value) // or maybe public ?!
{
...
...
if (pBox != null) pBox.Image = photos[x];
x++;
}
}
Create the class instance like this:
Execute someName = new Execute(pictureBox1);
Note that there are other ways to solve this; this is just a rather direct and straightforward one. If your class is a kind of service class you may want to go with Tarek's even more direct solution. Note that he not just adds the PictureBox to the parameter list. He also makes the function public.

Calling object from mainform.cs in other forms?

i want to call anything from mainform (mainform.cs) from GraficDisplay (namespace)
in the other (namespace) : GraphLib , but i can't , would any one tell me why? and how can i resolve this problem? Its been giving me hard time since the start of the project, every time I try these errors appear:
When I call:
mainform.toolstriplabel1.text = "87";
this appears:
The name 'mainform' does not exist in the current context
and if I call this:
GraficDisplay.MainForm.toolstriplabel1.text = "87";
this appears:
The name 'GraficDisplay' does not exist in the current context
I mean I even can't call the GraficDisplay (namespace) in GraphLib (namespace)
also the MainForm is public and partial.
I usually don't follow links here either but CodeProject is a rather reliable source imo, so I had a look.
Edit: I was confused as to what you want. Here is what you seem to actually wnat:
The problem is about referencing a form or part of it from another form or part of it. It is further a problem of dealing with a Library, that really shouldn't be messed up be adding namespaces of an example application or dependencies etc..
So what you want is loose coupling.
Here is a solution that uses references in the library objects and register methods to fill the references. If you don't register anything the library will work normally.
This solution can be changed and expanded but I'll leave it at registering two objects: One is a Control, eg.g a TextBox; the other is a Component e.g. a ToolStripItem. If you want to reference only the ToolStripItem you can omit the references to the Control and the RegisterCtl methods.
In hat case you can and should also substitute 'Component' for 'ToolStripItem' to make things thighter!
First you go to the ultimate consumer of the actions, PlotterGraphSelectCurvesForm. Here you add these two blocks of code:
public partial class PlotterGraphSelectCurvesForm : Form
{
private int selectetGraphIndex = -1;
private PlotterGraphPaneEx gpane = null;
// block one: a Control reference (if you like!):
Control myTextCtl;
public void RegisterCtl(Control ctl) { if (ctl != null) myTextCtl = ctl; }
// block one: a Component reference:
Component myTextComp;
public void RegisterComp(Component comp) { if (comp != null) myTextComp = comp; }
//..
Next you code what you want to happen, maybe like this:
void tb_GraphName_TextChanged(object sender, EventArgs e)
{
if (selectetGraphIndex >= 0 && selectetGraphIndex < gpane.Sources.Count)
{
DataSource src = gpane.Sources[selectetGraphIndex];
String Text = tb_GraphName.Text;
// all controls have a Text:
if (myTextCtl != null) myTextCtl.Text = Text;
// here you need to know the type:
if (myTextComp != null) ((ToolStripItem) myTextComp).Text = Text;
//..
}
In theory all you now need to do is to register the TextBox and/or the ToolStripItem in the Mainform.. However, there is a complication: The PlotterGraphSelectCurvesForm is not called from the Mainform! Instead it is called from a UserObject PlotterGraphPaneEx, which in turn is sitting in the MainForm. In the same sprit of not messing up the library by creating dependencies you simply add the very same references and registration methods to this UO as well:
public partial class PlotterDisplayEx : UserControl
{
#region MEMBERS
Control myTextCtl;
public void RegisterCtl(Control ctl) { if (ctl != null) myTextCtl = ctl; }
Component myTextComp;
public void RegisterComp(Component comp) { if (comp != null) myTextComp = comp; }
//..
Now you can actually register things, both in the MainForm..:
public MainForm()
{
InitializeComponent();
display.RegisterCtl(aDemoTextBox);
display.RegisterComp(toolstriplabel1);
//..
..and in the UO:
private void selectGraphsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (GraphPropertiesForm == null)
{
GraphPropertiesForm = new PlotterGraphSelectCurvesForm();
GraphPropertiesForm.RegisterCtl(myTextCtl);
GraphPropertiesForm.RegisterComp(myTextComp);
}
//..
Now when you open the Properties form and change the LabelText you can see both the text in the Graphs and the text in both the Menu and the TextBox change..

C# Call function in a class from another class

I'll start of by saying I'm not a developer. Yes this is a c# nightmare. But this is a one time tool and thats it. Quick and Dirty it just needs to work and thats it.
I have the following code:
public string[] get_status(string local_fname)
{
var dts_doc = new HtmlAgilityPack.HtmlDocument();
dts_doc.Load(local_fname);
//Pull the values
var ViewState = dts_doc.DocumentNode.SelectSingleNode("/html[1]/body[1]/div[1]/input[4]/#value[1]");
var EventValidation = dts_doc.DocumentNode.SelectSingleNode("/html[1]/body[1]/div[2]/input[1]/#value[1]");
string ViewState2 = ViewState.Attributes[3].Value;
string EventValidation2 = EventValidation.Attributes[3].Value;
//Display the values
//System.Console.WriteLine(ViewState.Attributes[3].Value);
//System.Console.WriteLine(EventValidation.Attributes[3].Value);
//System.Console.ReadKey();
return new string[] { ViewState2, EventValidation2 };
}
I want to call get_status from a button on my Main.cs which will show 2 Message Boxes with ViewState2 and EventValidation2.
Again, I'm not a developer, this is probably the wrong way of doing things. But I just need a quick and dirty solution to get this job done once.
Make the function static by adding the static keyword to the function definition:
static public string[] get_status(string local_fname)
Use the class name to reference the function from your Main class.
try this:
foreach(string s in get_status(localFname))
{
MessageBox.Show(s);
}
As you said, it is quick and dirty and I stayed faithful to that paradigm.
And yes, if you need to acces another class, make the method static or just simply create an instance and call the method on it. I hope I have understood the problem correctly.
if you are using visual studio, go to the Button you want to click, double-click the button. This will create an eventhandler. In the eventhandler you should call the above method.
protected void Button1_Click(object sender, eventArgs e)
{
string local_fname = someValue;
string results[] = get_status(local_fname);
MessageBox.Show(results[0]);
MessageBox.Show(results[1]);
}

Categories

Resources