Application wide component

J

Joe

Is it possible to have a component which is global to the entire
application? I need to have a single component act sort of like a server
which components in any of the forms can access.

For example if I drop a component on Form1 & Form2 and that component has a
property called Server, at design time I would like to be able to assign the
global component to the Server property.

I'm sure I'm asking for way too much...

Thanks for any help,
Joe
 
D

Dave Sexton

Hi Joe,

You can use the singleton pattern to ensure that only a single instance of
your server component may be used:

sealed class GlobalServer
{
public static readonly GlobalServer Instance = new GlobalServer();

public object GlobalState
{
get { return globalState; }
set { globalState = value; }
}

private static object globalState;

// remove the private constructor (or add a public one)
// if you want to allow creation of instances that aren't
// shared (see comments below)
private GlobalServer() { }
}

In your "client" components, you don't have to assign them any reference.
Just use GlobalServer.Instance directly or wrap it in a property:

class Client : Component
{
public GlobalServer Server
{
get
{
return GlobalServer.Instance;
}
}
}

If you need to be able to assign different instances of GlobalServer to your
Client component then simply add a "set" accessor with a local field in
which to store the reference. To assign an instance in the Form designer
using the Properties window, your GlobalInstance component would have to
derive from Component as well and must be added to the Form, but then it
will no longer be a shared (global) instance. You'll also have to indicate
to the PropertyGrid which Types are allowable for your Server property. You
can use a base editor that I made for one of my projects:

// 2.0 framework code

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel.Design;
using System.ComponentModel;
using System.Windows.Forms;

namespace YourLibrary
{
public abstract class ComponentSelectorEditor<T> : ObjectSelectorEditor
where T : class, IComponent
{
public ComponentSelectorEditor()
{
}

protected override void FillTreeWithData(Selector selector,
System.ComponentModel.ITypeDescriptorContext context, IServiceProvider
provider)
{
selector.Clear();
selector.AddNode("(none)", null, null);

Type baseType = typeof(T);

IReferenceService referenceService =
provider.GetService(typeof(IReferenceService)) as IReferenceService;

foreach (IComponent component in context.Container.Components)
{
if (baseType.IsAssignableFrom(component.GetType()))
{
string name = null;

if (component != null && component.Site != null)
name = component.Site.Name;
else if (referenceService != null)
name = referenceService.GetName(component);
else
throw new InvalidOperationException("There is no service available to
retrieve the name of one or more components.");

selector.AddNode(name, component, null);
}
}
}
}
}

With this base editor you can derive an editor that will allow properties to
bind to "GlobalServer" components:

public sealed class ServerSelectorEditor
: ComponentSelectorEditor<GlobalServer> // base component Type
{
// no implementation required :)
}

Note: GlobalServer should be renamed to Server since it's not global anymore

The editor above can be assigned to your Server property like this:

class Client : Component
{
private GlobalServer server;

[Editor(typeof(ServerSelectorEditor),
typeof(System.Drawing.Design.UITypeEditor))]
[DefaultValue(null)] // not req. but recommended
public GlobalServer Server
{
get { return server; }
set { server = value; }
}
}


NOTE: You may need to build the solution and then close and restart VS for
the changes to take affect, or else you might not see any GlobalServer
components in the list even though some have been added to the Form
designer.

You could code instances of GlobalServer to access only static resources, so
in a sense you could actually do what you wanted using the editor above,
however I'd recommend using the first scenario for that and foregoing the
designer support if you don't actually need instances of GlobalServer.
 
J

Joe

Hi Dave,

Thanks for the info. It seems like it should give me exactly what I'm
looking for but the client control doesn't see the GlobalServer at design
time if they're on different forms.

I may just go with hard coding the static reference into the clients. I had
wanted to avoid this so other developers won't go crazy trying to figure out
how the client controls get a connection to the server.

Thanks again,
Joe

Dave Sexton said:
Hi Joe,

You can use the singleton pattern to ensure that only a single instance of
your server component may be used:

sealed class GlobalServer
{
public static readonly GlobalServer Instance = new GlobalServer();

public object GlobalState
{
get { return globalState; }
set { globalState = value; }
}

private static object globalState;

// remove the private constructor (or add a public one)
// if you want to allow creation of instances that aren't
// shared (see comments below)
private GlobalServer() { }
}

In your "client" components, you don't have to assign them any reference.
Just use GlobalServer.Instance directly or wrap it in a property:

class Client : Component
{
public GlobalServer Server
{
get
{
return GlobalServer.Instance;
}
}
}

If you need to be able to assign different instances of GlobalServer to
your Client component then simply add a "set" accessor with a local field
in which to store the reference. To assign an instance in the Form
designer using the Properties window, your GlobalInstance component would
have to derive from Component as well and must be added to the Form, but
then it will no longer be a shared (global) instance. You'll also have to
indicate to the PropertyGrid which Types are allowable for your Server
property. You can use a base editor that I made for one of my projects:

// 2.0 framework code

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel.Design;
using System.ComponentModel;
using System.Windows.Forms;

namespace YourLibrary
{
public abstract class ComponentSelectorEditor<T> : ObjectSelectorEditor
where T : class, IComponent
{
public ComponentSelectorEditor()
{
}

protected override void FillTreeWithData(Selector selector,
System.ComponentModel.ITypeDescriptorContext context, IServiceProvider
provider)
{
selector.Clear();
selector.AddNode("(none)", null, null);

Type baseType = typeof(T);

IReferenceService referenceService =
provider.GetService(typeof(IReferenceService)) as IReferenceService;

foreach (IComponent component in context.Container.Components)
{
if (baseType.IsAssignableFrom(component.GetType()))
{
string name = null;

if (component != null && component.Site != null)
name = component.Site.Name;
else if (referenceService != null)
name = referenceService.GetName(component);
else
throw new InvalidOperationException("There is no service available to
retrieve the name of one or more components.");

selector.AddNode(name, component, null);
}
}
}
}
}

With this base editor you can derive an editor that will allow properties
to bind to "GlobalServer" components:

public sealed class ServerSelectorEditor
: ComponentSelectorEditor<GlobalServer> // base component Type
{
// no implementation required :)
}

Note: GlobalServer should be renamed to Server since it's not global
anymore

The editor above can be assigned to your Server property like this:

class Client : Component
{
private GlobalServer server;

[Editor(typeof(ServerSelectorEditor),
typeof(System.Drawing.Design.UITypeEditor))]
[DefaultValue(null)] // not req. but recommended
public GlobalServer Server
{
get { return server; }
set { server = value; }
}
}


NOTE: You may need to build the solution and then close and restart VS for
the changes to take affect, or else you might not see any GlobalServer
components in the list even though some have been added to the Form
designer.

You could code instances of GlobalServer to access only static resources,
so in a sense you could actually do what you wanted using the editor
above, however I'd recommend using the first scenario for that and
foregoing the designer support if you don't actually need instances of
GlobalServer.

--
Dave Sexton

Joe said:
Is it possible to have a component which is global to the entire
application? I need to have a single component act sort of like a server
which components in any of the forms can access.

For example if I drop a component on Form1 & Form2 and that component has
a property called Server, at design time I would like to be able to
assign the global component to the Server property.

I'm sure I'm asking for way too much...

Thanks for any help,
Joe
 
D

Dave Sexton

Hi Joe,
Thanks for the info. It seems like it should give me exactly what I'm
looking for but the client control doesn't see the GlobalServer at design
time if they're on different forms.

Yes, the editor only looks for server components on the same Form as the
client component, which is why you must add a new server instance to each
form. Since each client will have their own server instance on each Form,
the server class is no longer "global", as I mentioned in my original
response.

Another approach would be to derive all of your components from a custom
base component class that has the Server property from my first example (the
one with no set accessor). That way, all of your components will use the
static server and won't have to be assigned each time they are added to a
form.

<snip>
 
J

Joe

Hi Dave,

I thought that would be the only way to handle this.
Thanks for your time,
Joe
 
K

Kevin Yu [MSFT]

Hi Joe,

You can me the modifier to public to make the GlobalServer seen from other
forms. Also, a better approach, is to create another class library project
e.g. named Common. You can add reference to this classs, so that
GlobalServer is form independent and can be seen from all forms.

If anything is unclear, please feel free to let me know.

Kevin Yu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
K

Kevin Yu [MSFT]

Hi Joe,

I'd like to know if this issue has been resolved yet. Is there anything
that I can help. I'm still monitoring on it. If you have any questions,
please feel free to post them in the community.

Kevin Yu
Microsoft Online Community Support
==================================================

(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
J

Joe

Yes this has been resolved. I ended up creating a static class which my
components all reference.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top