c# - use variables from different methods - c#

Im not sure im going about this the right way or not, so hopefully somebody can help me.
Im trying to use a var in a method, which is contained in a different method. As expected, I get the error: The name 'Title1' does not exist in the current context .
first im reading an xml file then populating bing maps with pushpins. One of the variables is the tite of each xml item, I need to use the "Title1" var on my method below.
Here is the code:
public void OnOpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
var document = XDocument.Load(e.Result);
if (document.Root == null)
return;
var xmlns = XNamespace.Get("http://www.blahblah.com");
var events = from ev in document.Descendants("item")
select new
{
Latitude = Convert.ToDouble(ev.Element(xmlns + "Point").Element(xmlns + "lat").Value),
Longitude = Convert.ToDouble(ev.Element(xmlns + "Point").Element(xmlns + "long").Value),
Title = (ev.Element("title").Value),
Description = (ev.Element("description").Value),
Link = (ev.Element("link").Value),
};
QuakeLayer.Children.Clear();
foreach (var ev in events)
{
var accentBrush = (Brush)Application.Current.Resources["PhoneAccentBrush"];
var Title1 = (ev.Title);
var pin = new Pushpin
{
Location = new GeoCoordinate
{
Latitude = ev.Latitude,
Longitude = ev.Longitude
},
Background = accentBrush,
Content = Title1
};
QuakeLayer.AddChild(pin, pin.Location);
}
}
public void Pushpin_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
NavigationService.Navigate(new Uri("/blahblah.xaml?info=" + Title1, UriKind.Relative));
}

If you use an anonymous method inside your loop you will be able to access this variable (magic happens during compilation):
var pin = new Pushpin
{
...
Content = Title1
};
pin.ManipulationStarted += (s, a) =>
{
// Code for the event here
// ... do something with Title1
};
QuakeLayer.AddChild(pin, pin.Location);

Is the PushPin the sender of the event? If so, you can get the title from it since you set that as it's content.
public void Pushpin_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
var pushPin = (PushPin)sender;
var title = pushPin.Content;
NavigationService.Navigate(new Uri("/blahblah.xaml?info=" + title, UriKind.Relative));
}

You can't reference local variables across different methods. For one thing, the local variable no longer exists when the function it's defined in returns. For another thing, it looks like the Title local variable will be assigned a lot of different values over the course of running through the events foreach loop, so moving the Title1 variable out to a class field won't solve anything.
Your best bet is probably to associate the Title1 with the pushpin object. What object is passed into your pushpin event as the sender? If that's the pushpin object itself, or the pushpin object is available via the event args parameter, then you're home free. The pushpin's Content property contains the Title1 value. Use Pushpin.Content instead of Title1.

Make it a class variable. Or pass it as an argument to another function. But the local variable is only valid inside a function. (A function can be called many times recursively. In that case, there are multiple copies of all the local variables in each stack frame. So what you're asking makes no sense.)

Since Title1 is created inside of a loop the only real "viable" method is for you to pass the item as a parameter to the object, OR to store he value that you need in a location that you could get it from. (Possibly as a Tag on the object that starts your other event).

Related

How do I use strings from XML as variable to create button? C#

To make this easier, I will show my code and then explain what im trying to do.
CODE+EXPLANATION:
First, when the user clicks on a button it goes to Other with additonal information.
private void button1_Click(object sender, EventArgs e)
=> Other("https://pastebin.com/raw/something", "Program1", "A");
private void button2_Click(object sender, EventArgs e)
=> Other("https://pastebin.com/raw/something", "Program2", "B");
Second, I download an XML document and extract neccesary information from it:
private void Other(string UniversalURL, string ProductNAME, string ProductCHANNEL)
{
//Download the Doc
XmlDocument document = new XmlDocument();
document.Load(UniversalURL);
string expandedEnvString = Environment.ExpandEnvironmentVariables("%USERPROFILE%/AppData/Local/Temp/zADU.xml");
File.WriteAllText(expandedEnvString, document.InnerXml);
XmlDocument doc = new XmlDocument();
doc.Load(expandedEnvString);
//Get the needed Nodes
XmlNode nodeXMLProgram = doc.DocumentElement.SelectSingleNode($"/{ProductNAME}");
string XMLProgram = nodeXMLProgram.InnerText;
// Creation of Button Here
}
GOAL: What I want to be able to do is use the strings, extracted from the XML and use them as variables in the creation of button, Kind of like this:
Button Program(XMLProgram) = new Button();
Program(XMLProgram).Height = 22;
Program(XMLProgram).Width = 122;
Program(XMLProgram).BackColor = Color.FromArgb(230, 230, 230);
Program(XMLProgram).ForeColor = Color.Black;
Program(XMLProgram).Name = "DynamicButton";
Program(XMLProgram).Click += new EventHandler(ProgramProgram(XMLProgram)_Click);
Program(XMLProgram).BringToFront();
Controls.Add(ProgramProgram(XMLProgram));
Would I be able to do this? Help would be appreciated! Sorry for confusing title, I don't know how to phrase it properly.
You can use Reflection to look for and set the properties of the object you are deserializing automatically, provided you have a properly formatted XML file.
Read your XML file through XDocument or XmlDocument, extract from it the type of control you need to create (button, textbox, etc), also extract the property names to set from the XML, and the values to set them to. Then create an instance of said control type, and use code like this to go through your property list from the XML and set them in your instance:
// New instance of the control (read the type from the XML and create accordingly)
var ctrlInstance = new Button();
// Get a reference to the type of the control created.
var ctrlType = ctrlInstance.GetType();
// Dictionary to contain property names and values to set (read from XML)
var properties = new Dictionary<string, object>();
foreach (var xmlProp in properties)
{
// Get a reference to the actual property in the type
var prop = ctrlType.GetProperty(xmlProp.Key);
if (prop != null && prop.CanWrite)
{
// If the property is writable set its value on the instance you created
// Note that you have to make sure the value is of the correct type
prop.SetValue(ctrlInstance, xmlProp.Value, null);
}
}
If you intend to create an entire program this way, including code, you will have to use Roslyn to compile your code at runtime, which can be somewhat complicated to put into practice. In that case, you don't need an XML file, you just need to put put all your code into a source file and compile it, then instantiate it in your own program. If you just want to create a form programmatically and handle events in its parent form, this will work fine.

How to load the correct image from my database to the correct item when I click on my pin?

So I have a map in my code with multiple pins. When I click on a pin I get to a newpage with the pintitle. That works but If I want to add an image/and or description to that same page (that I also store on my database, parse) it doesnt work as I only get the topimage stored in the database on every different pin i click.
string picture;
string theDescription;
var getItems = await parseAPI.getInfo (Application.Current.Properties ["sessionToken"].ToString ()); //I load my data.
foreach (var currentItem in getItems["results"])
{
var prodPic = "";
if(currentItem["image"] != null)
{
prodPic = (string)currentItem ["image"] ["url"];
}
picture = prodPic; //i add the picture.
theDescription = currentItem ["description"].ToString (); // i add the descrption
dName = currentItem ["name"].ToString (); //and the title
var pin = new Pin ();
pin.Position = new Position (16,13);
pin.Label = dName; //and then i connect my title here so it works, but how should I do it with my picture + description?
pin.Address = "click for info";
pin.Clicked += onButtonClicked1;
theMap.Pins.Add (pin); //adding my pins to my map.
}
void onButtonClicked1 (object sender, EventArgs e)
{
Pin pin = (Pin)sender;
Navigation.PushAsync (new DetailPage (pin.Label, picture, theDescription )); //label works, so every pin get a unique label, but picture + the description remains the same inside the item i enter.
}
so It works with the title, and that is because I have connected the pin to my onbuttonclicked1 (pin.label) function I assume? so I how should I do it with my image + description so the pin does not get the same picture + description on every pin i enter
UPDATED IDEA:
new List <String> ourItems = new List<String> ();
ourItems.Add (theDescription);
ourItems.Add (picture);
Like this? and then somehow connect them into my OnButtonClicked1 function?
You are running a foreach loop which repeatedly sets the same "picture" variable. That is, every time you iterate, you are setting the "picture" and "description" variables to whatever value is relevant for the current iteration without actually persisting any of the previous values anywhere.
Your loop would look something like this:
Iteration one: picture = "pictureOne.png";
Iteration two: picture = "pictureTwo.png";
Iteration three: picture = "PictureThree.png";
...etc
What this means is that by the time your loop ends, you will have reset your imagine multiple times, with the variable retaining its last set value (in the above example that would be "pictureThree.png"
One way (not necessarily the best, mind you) would be to have an empty list, which you then populate from within the loop.

How do I get data from multiple XML files in Windows Phone

I have an initial XML file stored in my phone which is accessed to select a number of elements. Each element has a corresponding online XML file which I need to access to get more information.
string name, photo;
foreach (int num in combi)
{
no = xElem.Descendants("employee").ElementAt(num).Descendants("no").First().Value;
WebClient wc = new WebClient();
wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler
(Info_DownloadStringCompleted);
wc.DownloadStringAsync(new Uri
("http://example.com/" + name));
list.Add(new Person(no, name, photo);
}
void Info_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null) return;
XElement xml = XElement.Parse(e.Result);
name = xml.Element("name").Value;
photo = xml.Element("photo").Value;
}
However, it seems that the list.Add goes first before the XML is downloaded resulting into a list with empty values for name and photo. I confirmed this by placing MessageBox in both the foreach loop and Info_DownloadStringCompleted. Is there a better way of doing this?
To add to #MikkoVitala's answer, better for you to use ObservableCollection for the list.
ObservableCollection has built-in mechanism to notify UI to refresh whenever item added to or removed from collection. So it doesn't matter when you bind list to ListBox, the ListBox will always display up to date member of list :
string name, photo;
ObservableCollection<Person> list = new ObservableCollection<Person>();
foreach (int num in combi)
{
.....
}
MyListBox.ItemsSource = list;
Problem with your solution is that in your iteration over combi you'll try to use fields name and photo which are only assigned to in your eventhandler Info_DownloadStringCompleted.
Since DownloadStringAsync is, well... asynchronous, you'll exit foreach before DownloadStringCompleted event is raised, your eventhandler called and ultimately your fields been assigned to.
You can correct this by moving your list-add-logic to be executed after event has been raised.
....
wc.DownloadStringCompleted += (sender, args) =>
{
// Code from your Info_DownloadStringCompleted event handler
if (args.Error != null)
return;
XElement xml = XElement.Parse(args.Result);
name = xml.Element("name").Value;
photo = xml.Element("photo").Value;
// Now your fields are assigned and you can do-what-ever-with-'em
list.Add(new Person(no, name, photo);
};
....
If you like you can use extension methods to utilize async/await keywords and make it simpler and easier to read and understand. See SO answer here https://stackoverflow.com/a/13174270/1061668
Then above becomes (remember to mark method async)
....
// Note that exception is not handled in this example....
xml = await wc.DownloadStringTask(new Uri("http://example.com/" + name));
name = xml.Element("name").Value;
photo = xml.Element("photo").Value;
list.Add(new Person(no, name, photo);
....

Declaring a new object via variable name

I'm fairly new to C# (and programming in general) so stick with me if I make any huge errors or talk complete bull.
So what I'm trying to do is have a private void that resizes the background image of a button. I send the name of the button to the private void via a string. Anyway, the code looks something like this:
ButtonResize("Zwaard");
protected void ButtonResize(string Button)
{
string ButNaam = "btn" + Button;
Button Butnaam = new Button();
Butnaam.Text = ButNaam;
if (Butnaam.BackgroundImage == null)
{
return;
}
else
{
var bm = new Bitmap(Butnaam.BackgroundImage, new Size(Butnaam.Width, Butnaam.Height));
Butnaam.BackgroundImage = bm;
}
}
But it doesn't work like that. I can't seem to find a way to declare a new object named the value I have in a string. What I want my code to do is instead of making a button called "Butnaam", I want it to create a button called btnZwaard (the value of the string Butnaam).
How do I tell C# I want the value of the variable to be the name of a new button, not literally what I type?
Thanks in advance.
Are you looking for something like this? By passing the Button to the method you can then act on the object. If this is what you are looking for then you should read Passing Reference-Type Parameters
protected void ButtonResize(Button button)
{
if (button != null && button.BackgroundImage != null)
{
button.BackgroundImage = new Bitmap(button.BackgroundImage, new Size(newWidth, newHeight));
}
}
A string is a piece of text. You subsequently refer to it as a class, which is wrong. Assuming it were right you create a new button rather than "resize its image".
What you want to do to get you started is create a new function in the same class as the dialog that has the button. That function can resize the image of the control.
Edit: this doesn't seem like a good starting point for learning a language, btw. Please find a good online tutorial for starting in C# (e.g. a hello world application).

Get resourcename of PictureboxImage

I've got a Picturebox, the user can select its backgroundimage out of a resource file.
Later I want to get the resourcename out of the picturebox.
I've already tried this:
MessageBox.Show(((PictureBox)sender).BackgroundImage.ToString());
But it gave me the format of the picture.. there isnt something like:
MessageBox.Show(((PictureBox)sender).BackgroundImage.Name.ToString());
and I've already thougt about setting a Tag to the Picturebox with the picturename when setting the Image... but this is annoying as hell...
So how can I get the name of the Resource used as the backgroundimage at a Picturebox easily?
I think i have to explain the whole situation:
Ive got a form with a lot of raidbuttons...
if you select one of those buttons and click on a panel,the panel changes to the selected radiobuttonimage...
the click event of the panel:
PanelClick(object obj ,...)
{
if(radiobuttonApple.checked)
{
obj.backgroundimage = resource.apple;
}
if(radiobuttonPear.checked)
{
obj.backgroundimage = resource.Pear;
}
}
and hundred more of those...
and later on i want to know wich resourcefile the backgroundimage is..
Isnt there something like this:
(if i would name the radiobuttons like the resources)
PanelClick(object obj ,...)
{
obj.backgroundimage = resource[selectedradiobutton.Name]
obj.tag = selectedradiobutton.Name
}
So now im about to use LINQ:
RadioButton checkedRadioButton = panel1.Controls.OfType<RadioButton>().FirstOrDefault(r => r.Checked);
obj.tag = checkedRadioButton.Text;
so i only need to know how to get a resource dinamical by name e.g.:
obj.backgroundimage = resource[checkedRadioButton.Text];
and ill use a resourcemanager :
var resman = new System.Resources.ResourceManager(
"RootNamespace.Pictures",
System.Reflection.Assembly.GetExecutingAssembly()
)
var image = resman.GetPicture("checkedRadioButton.Text");
i hope this will work ..
Create a method to return the resource based on the selected radio button.
Example:
private resource checkResource()
{
if(radiobuttonApple.checked)
{
return resource.apple;
}
if(radiobuttonPear.checked)
{
return resource.Pear;
}
}
Then you can use it like this:
PanelClick(object obj ,...)
{
obj.backgroundimage = checkResource();
}
or
PanelClick(object obj ,...)
{
obj.backgroundimage = checkResource();
obj.tag = selectedradiobutton.Name
}
EDIT:
As you said, this approach can have different problems based on the number of iterations for each assignment. To avoid this and also in the light of another solution, you can use a single event to handle all the radio button state changes like this:
First, create a resource variable to be assigned to whenever a radioButton's status changes. ie.
private Resource bgResource;
private void radioButton_CheckedChanged(object sender, EventArgs e)
{
RadioButton obj = sender as RadioButton;
bgResource = resman.GetPicture(obj.Tag);
}
Then any time you want to change background you can simply say:
obj.BackgroundImage = bgResource;

Categories