Хорошо, поэтому я столкнулся с проблемой, не слишком отличавшейся ранее, но не с WPF, поэтому примите следующее (очень смешное) предложение с щепоткой соли.
Следующий метод в основном создает совершенно отдельный поток приложения для запуска команд DirectShow, но указывает прямому шоу использовать дескриптор элемента управления Windows Form, размещенного в вашем приложении WPF.
Итак, сначала нам нужна фиктивная форма WinForms, которую мы можем использовать для вызова вызовов, но она никогда не будет обработана:
/// <summary>
/// Just a dummy invisible form.
/// </summary>
private class DummyForm : Form
{
protected override void SetVisibleCore(bool value)
{
//just override here, make sure that the form will never become visible
if (!IsHandleCreated)
{
CreateHandle();
}
value = false;
base.SetVisibleCore(value);
}
}
Следующий шаг - создать поток, в который мы можем поместить цикл сообщений:
//this will need to be a class level variable, since all the directshow
//calls will get invoked on this form
DummyForm dumbForm;
Thread separateThread;
private void CreateDummyForm()
{
ManualResetEvent reset = new ManualResetEvent(false);
//create our thread
separateThread = new Thread((ThreadStart)
delegate
{
//we need a dummy form to invoke on
dumbForm = new DummyForm();
//signal the calling method that it can continue
reset.Set();
//now kick off the message loop
Application.Run(dumbForm);
});
//set the apartment state of this new thread to MTA
separateThread.SetApartmentState(ApartmentState.MTA);
separateThread.IsBackground = true;
separateThread.Start();
//we need to wait for the windowing thread to have initialised before we can
//say that initialisation is finished
reset.WaitOne();
//wait for the form handle to be created, since this won't happen until the form
//loads inside Application.Run
while (!dumbForm.IsHandleCreated)
{
Thread.Sleep(0);
}
}
Итак, после создания фиктивной формы (и ее потока) вы можете вызывать вызовы на MTA.
Тема приложения выглядит так:
/// <summary>
/// Blank delegate, used to represent any Invoke or BeginInvoke target method.
/// </summary>
public delegate void InvokeHandler();
//i'm assuming here that DSComponent is a class that all your directshow
//code is in, and externalControl is the WinForms control you have embedded in
//your application.
dumbForm.Invoke(new InvokeHandler(delegate
{
//maybe something like this?
DSComponent.Start(externalControl);
}));
//and to stop it...
dumbForm.Invoke(new InvokeHandler(delegate
{
DSComponent.Stop();
}));
Затем, когда вы закончите работу с Directshow, закройте отдельную ветку приложения следующим образом:
//to end the separate thread and application loop,
//just close your invisible form
dumbForm.Close();
Преимущество этого подхода в том, что вы аккуратно помещаете песочницу в отдельную ветку. Недостатком является переключение контекста вызовов Invoke, а также накладные расходы на наличие другого потока приложения. Возможно, вам понравится добавить это в вашу текущую архитектуру, но это должно помочь.
Дайте мне знать, как вы поживаете, я заинтригован, насколько хорошо это работает.