Потому что вы можете легко зайти в тупик (среди других вопросов).
Например, ваш вторичный поток может пытаться обновить элемент управления UI, но элемент управления UI будет ожидать освобождения ресурса, заблокированного вторичным потоком, поэтому оба потока в конечном итоге ожидают завершения друг друга. Как прокомментировали другие, эта ситуация не уникальна для кода пользовательского интерфейса, но особенно распространена.
В других языках, таких как C ++, вы можете попробовать это сделать (без исключения, как в WinForms), но ваше приложение может зависнуть и перестать отвечать в случае возникновения тупика.
Кстати, вы можете легко сообщить потоку пользовательского интерфейса, что вы хотите обновить элемент управления, просто создать делегат, а затем вызвать (асинхронный) метод BeginInvoke для этого элемента управления, передав его вашему делегату. Э.Г.
myControl.BeginInvoke(myControl.UpdateFunction);
Это эквивалентно выполнению C ++ / MFC PostMessage из рабочего потока