How to create a context that you can access?
Is it possible to create a context that is accessible from a set of windows but not from a different set?
For example, two web request are running in their own context and objects like ServiceSecurityContext.Current
are pointing to different instances.
My application is a Word like application with a PlanWindow
that open a plan document. I woul开发者_Python百科d like to be able to do something like PlanContext.Current
which would return me the current plan, instead of having to pass the document around to any dialog that is opened from this PlanWindow
.
I presume that this has something to do with threading but I don't know where to start.
I had tackled a similar problem in one of my projects. I used the GetData and SetData methods of System.Runtime.Remoting.Messaging.CallContext.
The CallContext is unique to each thread and you can use it to store objects that are specific to the thread.
In this particular scenario, I would create a PlanContext class like this:
public class PlanContext
{
const string _PlanDocumentSessionKey = "Current_PlanDocument";
public static PlanDocument Current
{
get
{
return CallContext.GetData(_PlanDocumentSessionKey) as PlanDocument;
}
set
{
CallContext.SetData(_PlanDocumentSessionKey,value);
}
}
}
And in code where you instantiate the document, add this:
PlanContext.Current = newDocument;
FYI, HttpContext.Current also uses CallContext to retrieve the Context for a particular thread.
How about solving this with the following architecture:
IPlanContextReceiver
{
public object StateByWichPlanContextCanDeciceWhatToReturn get;
}
class SomeWindow : Window, IPlanContextReceiver
And in PlanContext, instead the Current property you have
public static PlanContext GetCurrent(IPlanContextReceiver receiver)
{
lock(contextSync) // be threadsafe if necessary
{
if(/*condition that checks receiver.StateByWichPlanContextCanDeciceWhatToReturn*/)
{
// context is valid for this receiver
// return the correct context from an internal store or similar
return Contexts["TheContextForCoolReceivers"];
}
else if(/*condition that checks receiver.StateByWichPlanContextCanDeciceWhatToReturn*/)
{
// context is valid for this receiver
// return the correct context from an internal store or similar
return Contexts["TheContextForUncoolReceivers"];
}
// no existing context is available for this receiver
return null;
}
}
If you make it a singleton again GetCurrent
could also be an instance method. And instead of a Method it could also be a indexer - that is a matter of taste.
Also, it is up to you what StateByWichPlanContextCanDeciceWhatToReturn
actually is. It could be as complex as multiple properties that need to be checked or it could be as simple as a string that you set once for each f your window context groups.
So here is another proposition wich work even if the active form is a dialog box :
1) Flag all your Window (child windows) with this interface :
public interface IPlanViewer
{
//this means that all you windows will have this property
PlanDocument Document { get; }
}
2) Create the "Context" class
public class Context
{
public static Context Current { get; set; }
public IPlanDocument Document { get; set; }
static Context()
{
Current = new Context();
}
}
3) In you MDI form handle the MdiChildActive event with this method
private void MdiForm_MdiChildActivate(object sender, EventArgs e)
{
var currentView = Form.ActiveForm as IPlanViewer;
if (currentView != null)
Context.Current.Document = currentView.Document;
}
4) Use this context like this
private void WorkWithCurrentDoc()
{
var doc = Context.Current.Document;
doc.Title = "totot"
// etc ...
}
That's it. Is it any better ?
Manitra.
A static dictionary? PlanContext[sessionID] ?
I think that this has nothing to do with threading.
If by Current
, you mean Selected or Active Plan
, then you can set a Property
on the PlanWindow
object that tracks the selected Plan (i.e: updated whenever a different plan is selected/activated) and have this property be accessible to all other windows/dialogs (make it static for example)
I've never done this, so I can only point you in a direction that seems correct.
First, here's how to use Application.Run on two threads to make to multiple "main" windows in a Windows Forms Application, each on their own thread:
http://msdn.microsoft.com/en-us/library/ms157901.aspx
Secondly, here's how to have per-thread state:
How does HttpContext.Current work in a multi-threaded environment?
http://blogs.msdn.com/jfoscoding/archive/2006/07/18/670497.aspx
First, i'll assume that you're application is a MDI Windows Form one and each child windows displays a document to the user.
1) Flag all your Window (child windows) with this interface :
public interface IPlanViewer
{
//this means that all you windows will have this property
PlanDocument Document { get; }
}
2) Create the "Context" class
public class Context
{
public static Context Current { get; set; }
static Context()
{
Current = new Context();
}
//The key method : I'm returning the document of the currently selected child windows or null if no windows are opened
public PlanDocument Document
{
get {
var currentView = Form.ActiveForm as IPlanViewer;
if (currentView != null)
return currentView.Document;
else
return null;
}
}
}
3) Use this context like this
private void WorkWithCurrentDoc()
{
var doc = Context.Current.Document;
doc.Title = "totot"
// etc ...
}
That's it. I hope this will help you.
Manitra.
精彩评论