开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜