Ничто не отличается между вашим сценарием и любым другим сценарием с межпоточным взаимодействием, за исключением того, что у вас есть много бесплатной работы, которую вы можете использовать, поскольку вы выполняете маршалинг между WPF и каким-либо другим потоком.
Короткая версия:
Когда вы получаете сообщение от другого клиента в вашем локальном стеке и вам нужно сообщить WPF, используйте Dispatcher.Invoke из сетевого потока, чтобы маршалировать вызов потока WPF, предположительно передавая ему какой-то объект Message. Это очень просто с лямбдами:
Сначала сохраните ссылку на диспетчер WPF в фоновом потоке во время инициализации приложения. Это легко, потому что (если вы не патологически многопоточны) ваш поток WPF является тем, который раскручивает ваш сетевой поток:
var guiDispatcher = Dispatcher.CurrentDispatcher;
Как только ваш другой поток сможет получить доступ к диспетчеру графического интерфейса, он может асинхронно запускать код в контексте этого диспетчера (в нашем случае, в потоке графического интерфейса WPF):
Message msg = myNetworkComms.GetMessage(); // or whatever
Action updateGui = () => myViewModel.ApplyNewMessage(msg);
guiDispatcher.BeginInvoke(DispatcherPriority.Normal, updateGui); // Run updateGui on GUI thread
Все это говорит, почему вы раскручиваете отдельный поток для своего сетевого ввода-вывода? Это кажется ужасно расточительным. Вы уверены, что нет никаких методов асинхронного сетевого ввода-вывода, которыми вы могли бы воспользоваться?