#c_sharp #wpf #net
Есть 2 программы. Одна WinPhone приложение, другая WPF. В обоих используется Dispatcher для доступа к элементам UI из потока. Вот код из WinPhone Dispatcher.BeginInvoke(() => RateTextBox.Text = rate) Здесь все работает. Dispatcher идет как объект, есть метод BeginInvoke. Вот код WPF Dispatcher.CurrentDispatcher.BeginInvoke(() => textBox1.Text = content) Здесь Dispatcher идет как класс, а не объект. Я не могу понять почему. Пытался испробовать разные конструкции, но в итоге идет ошибка Ошибка 2 Невозможно преобразовать "лямбда-выражение" к типу "System.Delegate", поскольку он не является делегатом Не могу понять почему ошибка и почему в двух проектах "разные" Dispatcher'ы, В WinPhone приложении подрублены свои мобильные библиотеки с коробки, ничего не добавлял от себя. В WPF Добавил WindowsBase.dll откуда взял ссылку на System.Windows.Threading где и лежит Dispatcher. Кто может разъяснить ситуацию? А то я уже больше недели бьюсь над этими вопросами. Почему на WinPhone все прекрасно работает как надо, а на WPF нет. Добавлено после: Теперь все компилица, но не выводит результат запроса. Я испробовал код на консольном приложении, где не требуется Dispatcher. Такой код (content => Console.WriteLine(content)) Здесь все работает. Но я добавил Dispatcher. (content => Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => Console.WriteLine(content)))) И консоль пуста.
Ответы
Ответ 1
Вам нужно явно указать тип делегата - любой, но конкретный тип. BeginInvoke принимает Delegate - делегат любого типа. Для компиляции лямбды как делегата компилятор должен знать тип. Он его не может вывести ни из сигнатуры метода - потому что там любой типа разрешен - ни из лямбды - потому что нет однозначного механизма вывода конкретного типа делегата только по параметрам и возвращаемому значению. Вот он и падает с ошибкой. Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => textBox1.Text = content)); P.S. Не используйте Invoke - намучаетесь. Используйте async/await.Ответ 2
WPF писался в до-дженериковую эру, и в нём осталось много наследия: нетипизирвоанные коллекции, невнятно типизированные делегаты и т. п. WinRT создавался уже в современную эпоху, поэтому в нём есть адекватные перегрузки методов. Лечится это просто — добавлением extension-методов. Например: public static class Exts { public static void BeginInvoke (this Dispatcher @this, Action action) { @this.BeginInvoke(action); } public static void BeginInvoke (this Dispatcher @this, DispatcherPriority priority, Action action) { @this.BeginInvoke(action, priority); } } При наличии такого класса будут работать привычные вам перегрузки. Впрочем, по возможности стоит использовать адаптированный для async/await метод — InvokeAsync: await Dispatcher.InvokeAsync(() => RateTextBox.Text = rate);Ответ 3
Компилятор не может вывести из вашей лямбды конкретный делегат, а потому сигнализирует об ошибке. Скастуйте его например так: Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => RateTextBox.Text = rate));Ответ 4
К вопросу о консоли. Dispatcher - это не какая-то магия, а класс, дающий доступ к стандартному виндовому циклу обработки сообщений. В консольном прилдожении никто не крутит этот цикл в основном потоке - вот и не работает Dispatcher.
Комментариев нет:
Отправить комментарий