Георгий Кузнецов, Как вариант создайте отдельную view модель, и вставьте туда готовую точно рабочую реализацию интерфейса (решарпер например ее генерирует), и сравните работает нет
Георгий Кузнецов, Чтобы убедиться, что команда вызывается. На вид все должно работать, но, как говорится, дьявол кроется в деталях - поэтому не вижу ничего плохого в добавлении временного кода для сокращения пространства возможных вариантов. Не нужно - не лепите, я же не заставляю :)
Георгий Кузнецов,
Насчёт MVVM - при правильной реализации ничего не виснет, т. к. WPF корректно перенаправляет события INotifyPropertyChanged в UI поток. Главный принцип - зависимости должны идти в одном направлении, т. е. если View это MainView.xaml/MainView.xaml.cs, а ViewModel - это MainViewModel.cs, то это значит, что MainView использует MainViewModel, а не наоборот. Это ведёт к тому, что вы не присваиваете руками значения свойствам контролов, а вместо этого контролы сами забирают что им надо из вью-модели, соответственно совершенно без разницы, в каком потоке вы её обновляете.
В правильной MVVM реализации у вас был бы какой-нибудь VideoPlayerBehavior, который бы как Behavior прикреплялся в визуальном дереве XAML к плееру и забирал оттуда прогресс, и предоставлял бы Attached Property для того, чтобы можно было привязать это значение к свойству во вью-модели при помощи механизма Binding.
Если видео-плеер никак не сигнализирует об изменении текущей позиции - то кроме таймера скорее всего и нет вариантов.
Если вдруг заинтересуетесь - вот на Хабре небольшая статья про Behavior'ы, с минимальной реализацией.
prostranstvovremya,
Вы нашли ответ на свой изначальный вопрос? Мне кажется это и есть критерий успешного поиска. Если хочется посмотреть на ещё более официальные сайты, попробуйте запрос "frap manufacturer".
Ну вам нужно было найти кран-буксу, я нашел и изложил свой ход мысли. Пользуйтесь расширенным поиском, заключайте ключевые слова в кавычки, используйте модификаторы site: и inurl:
Например пишете "модель смесителя" "обсуждение", или site:ваш_любимый_сайт_на_котором_обсуждают_смесители "модель" - кавычки обеспечивают поиск полного соответствия того, что написано в них. И либо находите, либо убеждаетесь, что в обозримом интернете никто эту модель не обсуждает.
NikolayKhablenko, Можно и одним сделать, было бы желание. Тогда вам нужно:
1. Сделать вашу лямбду асинхронной (добавить async перед ())
2. Заменить Thread.Sleep на await Task.Delay, передать туда ваш токен отмены
3. Там, где показываете следущее изображание, отменяете токен и ждете таск, и только после этого запускаете следующий
Петр, Я не стал углубляться в тонкости, если там действительно на ваш взгляд есть проблема - легким движением руки Semaphore превращается в SemaphoreSlim, а WaitOne() - в WaitOneAsync(), проблема надуманная я бы сказал
NikolayKhablenko,
Смотрите, в Dispatcher.Invoke делать Thread.Sleep ни в коем случае нельзя - это приводит к задержкам в UI. Оборачивайте в Dispatcher.Invoke только то, что требует UI потока.
Отвечая на ваш предыдущий вопрос - вы можете сделать два контрола на одном и том же месте, и показывать один из них в зависимости от того, что вам нужно - gif или не gif. Также есть небольшая возможность, что можно одновременно и то и то показывать - но это нужно пробовать. Имею ввиду, для обычных картинок задавать Source и опустошать gif:AnimationBehavior.SourceUri, и наоборот, для gif-картинок задавать gif:AnimationBehavior.SourceUri и опустошать Source.
Петр, Верно, есть и получше способы, семафоры при определенном желании можно ждать и асинхронно (WaitHandle/ThreadPool.RegisterWaitForSingleObject), или взять SemaphoreSlim, который умеет ждать асинхронно из коробки. Дело в том что это мало отношения имеет непосредственно к отображению GIF.
Петр, Как раз семафор можно помещать внутри Task, т. к. этот примитив синхронизации не обладает thread affinity - а значит, отработает, как и ожидается.