Ответ 1
Ну, у меня есть метод, который работает - но он может быть не самым элегантным..
У меня есть окно, содержащее элемент управления третьей стороной (медленный рендеринг) в XAML.
public partial class MapWindow : Window
{
private ConcurrentQueue<MapCommand> _mapCommandQueue;
private HwndSource _source;
// ...
}
Мой основной (UI) поток конструирует и запускает это окно в потоке:
_leftTopThread = new Thread(() =>
{
_topLeftMap = new MapWindow()
{
WindowStartupLocation = WindowStartupLocation.Manual,
CommandQueue = _leftMapCommendQueue,
};
_topLeftMap.Show();
System.Windows.Threading.Dispatcher.Run();
});
_leftTopThread.SetApartmentState(ApartmentState.STA);
_leftTopThread.IsBackground = true;
_leftTopThread.Name = "LeftTop";
_leftTopThread.Start();
Затем я получаю дескриптор окна в потоке (после его инициализации):
private IntPtr LeftHandMapWindowHandle
{
get
{
if (_leftHandMapWindowHandle == IntPtr.Zero)
{
if (!_topLeftMap.Dispatcher.CheckAccess())
{
_leftHandMapWindowHandle = (IntPtr)_topLeftMap.Dispatcher.Invoke(
new Func<IntPtr>(() => new WindowInteropHelper(_topLeftMap).Handle)
);
}
else
{
_leftHandMapWindowHandle = new WindowInteropHelper(_topLeftMap).Handle;
}
}
return _leftHandMapWindowHandle;
}
}
.. и после ввода команды в потокобезопасную очередь, которая совместно используется в потоковом окне:
var command = new MapCommand(MapCommand.CommandType.AircraftLocation, new object[] {RandomLatLon});
_leftMapCommendQueue.Enqueue(command);
.. Я дал понять, что может проверить очередь:
PostMessage(LeftHandMapWindowHandle, MapWindow.WmCustomCheckForCommandsInQueue, IntPtr.Zero, IntPtr.Zero);
Окно может получить мое сообщение, потому что оно подключилось к сообщениям окна:
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
_source = PresentationSource.FromVisual(this) as HwndSource;
if (_source != null) _source.AddHook(WndProc);
}
.. который он может проверить:
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) //
{
// Handle messages...
var result = IntPtr.Zero;
switch (msg)
{
case WmCustomCheckForCommandsInQueue:
CheckForNewTasks();
break;
}
return result;
}
.. и затем выполнить в потоке!
private void CheckForNewTasks()
{
MapCommand newCommand;
while (_mapCommandQueue.TryDequeue(out newCommand))
{
switch (newCommand.Type)
{
case MapCommand.CommandType.AircraftLocation:
SetAircraftLocation((LatLon)newCommand.Arguments[0]);
break;
default:
Console.WriteLine(String.Format("Unknown command '0x{0}'for window", newCommand.Type));
break;
}
}
}
Просто как это..:)