Итак ...
Похоже, информация / код @ http://geekswithblogs.net/robp/archive/2008/03/28/why-doesnt-dispatcher-implement-isynchronizeinvoke.aspx действительно обеспечивает рабочее решение.
Код полностью независим от любого пользовательского интерфейса и вместо этого зависит только от ISynchronizeInvoke для правильной интеграции пользовательского интерфейса / потока.
Просто воспользовавшись этим, я все еще неохотно оставляю все как есть.
Суть моей проблемы в том, что каждая функция вызова события выглядит примерно так:
protected virtual void OnLeftThumbStickMove(ThumbStickEventArgs e)
{
if (LeftThumbStickMove == null) return;
if (_syncObj == null || !_syncObj.InvokeRequired)
LeftThumbStickMove(this, e);
else
_syncObj.BeginInvoke(LeftThumbStickMove, new object[] { this, e });
}
Написание кода таким способом очень раздражает и сбивает с толку, мне кажется, это слишком много суеты вокруг того, чтобы заставить эту чертову штуку работать. По сути, мне не нравится, когда приходится оборачивать каждый вызов события такой большой логикой (!)
Поэтому я выбрал другую / дополнительную стратегию:
По сути, конструктор для класса XBox360GamePad теперь выглядит следующим образом:
public XBox360GamePad(UserIndex controllerIndex, Func<int, Action, object> timerSetupAction)
{
CurrentController = new Controller(controllerIndex);
_timerState = timerSetupAction(10, UpdateState);
}
Как видите, он принимает Func, который отвечает за создание таймера и его подключение.
Это означает, что по умолчанию ВНУТРИ класса 360 Controller мне не нужно использовать какие-либо
Таймеры, специфичные для пользовательского интерфейса ... По сути, мой конструктор по умолчанию для контроллера выглядит так:
public XBox360GamePad(UserIndex controllerIndex) :
this(controllerIndex, (i,f) => new Timer(delegate { f(); }, null, i, i)) {}
Я использую лямбда-функцию для кодирования зависимости класса контроллера от «службы» таймера.
Из WPF я использую более общий конструктор, чтобы гарантировать, что элемент управления будет использовать DispatcherTimer следующим образом:
_gamePad = new XBox360GamePad(UserIndex.One, (i, f) => {
var t = new DispatcherTimer(DispatcherPriority.Render) {Interval = new TimeSpan(0, 0, 0, 0, i) };
t.Tick += delegate { f(); };
t.Start();
return t;
});
Таким образом, я в основном оставляю это на усмотрение «пользователя», чтобы предоставить реализацию таймера для элемента управления, где реализация по умолчанию не должна использовать какой-либо специальный код WPF или WinForms.
Лично я считаю этот дизайн более полезным / приятным, чем использование ISynchronizeInvoke.
Мне бы очень хотелось услышать отзывы людей, которым это нравится / которые хотят это улучшить / мне это противно и т. Д.