views:

288

answers:

3

*Update: making the userIP static seemed to work. However, I learned that MainPage() is exectuting before Application_Startup(), so the InitParam values aren't immediately available. I may have to put my code somewhere else.*

I'm writing a Silverlight App and am taking in a variable in InitParams and I want that variable to be accessible in some way to other areas of my code. I'd prefer not to immediately assign the value to an element in XAML and instead use C# if possible. I have to do another step before I use the data to modify the XAML. Here's what I did so far:

In my App.xaml.cs file, I added a string userIP to the App class in hopes of accessing this value later. I then try to assign the value of the InitParams variable to the userIP string that I made above. Here's how it looks.

namespace VideoDemo2
{
    public partial class App : Application
    {
        public string userIP;
        public App()
        {
            this.Startup += this.Application_Startup;
            this.Exit += this.Application_Exit;
            this.UnhandledException += this.Application_UnhandledException;

            InitializeComponent();
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            this.RootVisual = new MainPage();
            this.userIP = e.InitParams["txtUserIP"];
        }
...}

The only lines I added to the code were public string userIP; and this.userIP = e.InitParams["txtUserIP"];. I'm wondering if this is the right way to go about this to make this data available later.

In my MainPage.xaml.cs file, I'm trying to reference the userIP value I specified earlier, but I can't figure out how to do so. For example, I want to create a new string and then set it to be equal to the userIP:

public MainPage()
{
    InitializeComponent();
    string myUserIP;
    myUserIP = VideoDemo2.App.userIP;
}

Then I get an error that says: Error 1 An object reference is required for the non-static field, method, or property 'VideoDemo2.App.userIP'.

I have to do something with the InitParams in App.xaml.cs because that's where the arguments are passed, but I want to make one of those parameters available to other parts of my application, without putting it in the XAML, if possible. What needs to happen so that I can "see" the value later on in the application? I'm brand new to C#, so any help would be very much appreciated.

A: 

The problem is that VideoDemo2.App is not an instance, but is a type.

If you want to access userIP, you need to access the actual instance of your app.

Silverlight provides a static property that exposes the current application instance:

App runningApp = (VideoDemo2.App)Application.Current;
string myUserIP = runningApp.userIP;

Or, you could make userIP a static string in App. You would remove "this" where it is set, but you could access it on the type from anywhere.

namespace VideoDemo2
{
    public partial class App : Application
    {
        public static string userIP;
        public App()
        {
            this.Startup += this.Application_Startup;
            this.Exit += this.Application_Exit;
            this.UnhandledException += this.Application_UnhandledException;

            InitializeComponent();
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            this.RootVisual = new MainPage();
            App.userIP = e.InitParams["txtUserIP"];
        }
...}
FlySwat
Don't do this - an App instance is created for you and held throughout the application lifecycle. See the Application.Current static property.
James Cadd
I wasn't saying he needs to instanciate an App, I was saying he needs to use the provided instance.
FlySwat
But that's what you show in your answer with App runningApp = new App(). You don't construct instances of the Application class in Silverlight, that's done for you.
James Cadd
His issue was not really silverlight related, it was a general misunderstanding between the concept of a type and an instance. I was guiding him towards the larger issue without focusing on the specific implementation. Regardless, I have clarified using the provided silverlight static class.
FlySwat
And encouraging creation of static properties doesn't add any style points - he's trying to learn C#, don't teach him bad form!
James Cadd
Says the man who told him to use a Singleton...speaking of bad form.
FlySwat
I'd disagree - this is definitely Silverlight specific as it relates to the Application lifecycle. That's not just any old class he put added that property too which is why you were wrong to assume he's instantiating it (he's not and shouldn't).
James Cadd
Ha, ok ok. Surely there's a better solution than singleton. Maybe a static class, maybe something else. Point taken.
James Cadd
I think I'm getting closer to understanding this. Either way, why or why not should I use a Singleton? I remember seeing that done before, but where can I go to learn the advantages/disadvantages?
Ben McCormack
Here's a good discussion of the disadvantages: http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons I didn't realize it was such a bad thing, sorry to point you in the wrong direction!
James Cadd
A: 

You can find your instance of the App class in the static property Application.Current. Try this from anywhere in your SL app:

((VideoDemo2.App)Application.Current).userIP;

EDIT: As an aside though, I would prefer to keep settings like this in a singleton class (its an easy pattern to implement in C#, quick search should be enough). Also for "good form" anything that's public should be a property and public properties should be pascal cased. Change the public string userIp to:

public string UserIP { get; set; }

And you'll win friends and influence people in no time ;)

EDIT: This is a good read about the lifecycle of the Application class in Silverlight http://msdn.microsoft.com/en-us/library/system.windows.application%28VS.95%29.aspx

James Cadd
Thanks Dale Carnegie!
Ben McCormack
And apparently Singleton really is a bad thing - don't do that and thanks to FlySwat for the heads up. http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons
James Cadd
I think I'm starting to wrap my head around why I should do things a certain way in OOP, but it's still difficult for me to approach when I come from a VBA world where I wrote nearly everything with procedures.
Ben McCormack
A: 

Both FlySwat and James Cadd's answers were helpful, but I found that for within Silverlight, using the Application's resource dictionary works best.

In the ASPX or HTML page, use the following <param> tag within your Silverlight <object> tag:

<param name="initParams" value="txtSomeVariable=SomeValue"/>

Then in the Application_Startup method of App.xaml.cs, use a foreach loop to add the values to the resource dictionary:

    private void Application_Startup(object sender, StartupEventArgs e)
    {
        //Method 1 - Resource Dictionary
        if (e.InitParams != null)
        {
            foreach (var item in e.InitParams)
            {
                this.Resources.Add(item.Key, item.Value);
            }
        }
        this.RootVisual = new MainPage();
    }

To pull the value from the dictionary during the life of your application, simply use:

App.Current.Resources["txtSomeVariable"].ToString();

I learned about InitParams and the Application Resource Dictionary from Tim Heuer's video presentation at Silverlight.Net: Using Startup Parameters with Silverlight.

Also, I wrote a blog post describing this situation in more detail: Pass the IP Address of a User to Silverlight as a Parameter.

I hope this information helps other users who stumble across this question!

Ben McCormack