Как создать контекст, к которому вы можете получить доступ? - PullRequest
0 голосов
/ 23 октября 2009

Можно ли создать контекст, доступный из набора окон, но не из другого набора?

Например, два веб-запроса выполняются в своем собственном контексте, а объекты типа ServiceSecurityContext.Current указывают на разные экземпляры.

Мое приложение - это приложение, подобное Word, с PlanWindow, которое открывает документ плана. Я хотел бы иметь возможность сделать что-то вроде PlanContext.Current, которое вернуло бы мне текущий план, вместо того, чтобы передавать документ в любой диалог, который открывается из этого PlanWindow.

Я предполагаю, что это связано с многопоточностью, но я не знаю, с чего начать.

Ответы [ 8 ]

1 голос
/ 07 ноября 2009

Я столкнулся с подобной проблемой в одном из моих проектов. Я использовал GetData и SetData методы System.Runtime.Remoting.Messaging.CallContext .

CallContext уникален для каждого потока, и вы можете использовать его для хранения объектов, специфичных для потока.

В этом конкретном сценарии я бы создал класс PlanContext следующим образом:

public class PlanContext
{
    const string _PlanDocumentSessionKey = "Current_PlanDocument";
    public static PlanDocument Current
    {
        get
        {
            return CallContext.GetData(_PlanDocumentSessionKey) as PlanDocument;
        }
        set
        {
            CallContext.SetData(_PlanDocumentSessionKey,value);
        }
    }
}

И в коде, где вы создаете экземпляр документа, добавьте:

PlanContext.Current = newDocument;

К вашему сведению, HttpContext.Current также использует CallContext для извлечения контекста для определенного потока.

1 голос
/ 03 ноября 2009

Как насчет решения этой проблемы со следующей архитектурой:

IPlanContextReceiver
{   
     public object StateByWichPlanContextCanDeciceWhatToReturn get;
}

class SomeWindow : Window, IPlanContextReceiver

А в PlanContext вместо свойства Current у вас есть

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;
    } 
}

Если вы снова сделаете его одиночным, GetCurrent также может быть методом экземпляра. И вместо Метода это также может быть индексатор - это дело вкуса.

Кроме того, вам решать, что на самом деле StateByWichPlanContextCanDeciceWhatToReturn. Он может быть таким же сложным, как несколько свойств, которые необходимо проверить, или может быть таким же простым, как строка, которую вы устанавливаете один раз для каждой группы контекста вашего окна.

1 голос
/ 06 ноября 2009

Итак, вот еще одно предложение, которое работает, даже если активная форма является диалоговым окном:

1) Отметьте все окна (дочерние окна) с помощью этого интерфейса:

public interface IPlanViewer
{
    //this means that all you windows will have this property
    PlanDocument Document { get; }
}

2) Создать класс «Контекст»

public class Context
{
    public static Context Current { get; set; }
    public IPlanDocument Document { get; set; }
    static Context()
    {
        Current = new Context();
    }
}

3) В вашей форме MDI обработайте событие MdiChildActive этим методом

private void MdiForm_MdiChildActivate(object sender, EventArgs e)
{
    var currentView = Form.ActiveForm as IPlanViewer;
    if (currentView != null)
        Context.Current.Document = currentView.Document;
}

4) Используйте этот контекст следующим образом

private void WorkWithCurrentDoc() 
{
    var doc = Context.Current.Document;
    doc.Title = "totot"
    // etc ...
}

Вот и все. Это лучше?

Manitra.

0 голосов
/ 06 ноября 2009

Во-первых, я предполагаю, что ваше приложение является формой MDI Windows, и каждое дочернее окно отображает документ для пользователя.

1) Отметьте все окна (дочерние окна) с помощью этого интерфейса:

public interface IPlanViewer
{
    //this means that all you windows will have this property
    PlanDocument Document { get; }
}

2) Создать класс «Контекст»

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) Используйте этот контекст следующим образом

private void WorkWithCurrentDoc() 
{
    var doc = Context.Current.Document;
    doc.Title = "totot"
    // etc ...
}

Вот и все. Я надеюсь, что это поможет вам.

Manitra.

0 голосов
/ 03 ноября 2009

Я не делаю C, но в Java у вас есть java.lang.ThreadLocal для этого.

public class MyClass {

    private static ThreadLocal<MyClass> instance = new ThreadLocal<MyClass>() {
        protected View initialValue() {
            return null;
        }
    };

    private MyClass(Object arg1, Object arg2) {
        this.arg1 = arg1; // Web request?
        this.arg2 = arg2; // Web response?
    }

    public static MyClass getInstance() {
        return instance.get();
    }

    public static MyClass createInstance(Object arg1, Object arg2) {
        MyClass myClass = new MyClass(arg1, arg2);
        setInstance(myClass);
        return myClass;
    }

    protected static void setInstance(MyClass myClass) {
        if (myClass == null) {
            instance.remove();
        } else {
            instance.set(myClass);
        }
    }

    public void release() {
        setInstance(null);
    }

}

Вы звоните createInstance() в тот момент, когда он должен быть создан впервые. Затем вы можете вызывать getCurrentInstance() в любой момент, когда захотите, продолжая работать в том же потоке.

Посмотрите, существует ли что-то подобное в C. Удачи.

0 голосов
/ 03 ноября 2009

Я думаю, что это не имеет ничего общего с потоками.

Если под Current вы подразумеваете Selected or Active Plan, то вы можете установить Property для объекта PlanWindow, который отслеживает выбранный план (т. Е. Обновляется всякий раз, когда выбирается / активируется другой план), и иметь этот свойство будет доступно для всех других окон / диалогов (например, сделайте его статическим)

0 голосов
/ 02 ноября 2009

Я никогда не делал этого, поэтому могу указать вам только направление, которое кажется правильным.

Во-первых, вот как использовать Application.Run в двух потоках для создания нескольких «главных» окон в приложении Windows Forms, каждое из которых имеет собственный поток:

http://msdn.microsoft.com/en-us/library/ms157901.aspx

Во-вторых, вот как получить состояние для каждого потока:

Как HttpContext.Current работает в многопоточной среде?

http://blogs.msdn.com/jfoscoding/archive/2006/07/18/670497.aspx

0 голосов
/ 23 октября 2009

Статический словарь? PlanContext [sessionID]?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...