Доступ к элементу управления WPF из неоконового класса - PullRequest
0 голосов
/ 28 октября 2009

Я новичок в WPF и у меня проблема с небольшим проектом. Я строю тестер для имитации устройства, которое управляется UDP. У меня есть пара классов, которые реализуют UDP как асинхронную реализацию. У меня было главное окно кода, опрашивающее приемный буфер для данных и обновления. Это сработало, но было очень неуклюжим. Поэтому я переместил весь код в асинхронный прием, где жил EndReceiveFrom. Это быстрее и избавляется от опроса. Но у меня больше нет доступа к элементам управления окна для их обновления.

Как я могу получить доступ к элементам управления за пределами окна? Окно создает экземпляр класса UDP, который все это выполняет, так что я могу передать вещи в вызов конструктора. У меня есть доступ, конечно, к приложению. Я знаю, что здесь что-то упущено.

Ричард

1 Ответ

2 голосов
/ 28 октября 2009

Прошло немного времени - поэтому я не буду предоставлять слишком много блоков кода - но звучит так, как будто вы хотите применить MVC или его двоюродных братьев MVP или MVVM. Не беспокойтесь о том, что они обозначают, но в целом они пытаются определить отношения между View [ваше окно], Data [ваши результаты с сетевого уровня] и Business [ваш сетевой уровень].

В вашем случае я бы порекомендовал MVVM. Если вы запустите Google, вы сможете найти множество информации о шаблоне дизайна и способах его применения. Снова, не суетитесь по теории слишком много. Просто к вашему сведению.

Далее немного мяса,

Концептуально, есть «данные», которые вы хотите представить в своем «представлении». Не беспокоясь о представлении, давайте сначала инкапсулируем ваши данные.

// name is a little too general, so just rename it to something
// specific in your source.
public class NetworkViewModel 
{
    // enumerate your data here
    public int Trouble { get; set; }
    public int Tribbles { get; set; }
    ...
}

Ваш взгляд - ваше окно. Пусть ваше представление создает экземпляр этой "модели представления"

public class MyNetworkMonitor
{
    ...
    // advanced: if you were injecting this - say from another source
    // or intended to replace the instance during runtime, there are
    // ways to deal with that. for now, we presume one instance for
    // application lifetime.
    public NetworkViewModel ViewModel { get; set; }
    public MyNetworkMonitor ()
    {
        ViewModel = new NetworkViewModel ();
    }
    ...
}

и в вашем Xaml свяжите со свойствами

// Xaml omitted, a limit to my memory :P
// but just regular binding to say ViewModel.Trouble

Хорошо. Поэтому, если ваша модель представления имеет начальное значение, оно будет отображаться в связанном элементе управления. К сожалению, если обновляются свойства модели представления, нет способа сообщить ограниченному элементу управления, что значение изменилось. Э-э, если, конечно, вы не реализуете общий интерфейс, который ищут привязки Wpf,

public class NetworkViewModel : INotifyPropertyChanged
{
    // defined by interface
    public event PropertyChangedEventHandler PropertyChanged;
    private int _trouble = 0;
    public int Trouble 
    {
        get { return _trouble; }
        set 
        {
            // 1. if value changes
            if (_trouble != value)
            {
                _trouble = value;
                // 2. inform whomever is listening!
                if (PropertyChanged != null) 
                {
                    PropertyChanged (
                        this, 
                        new PropertyChangedEventArgs ("Trouble"));
                }
            }
        }
    }
}

Конечно, вы можете обернуть и сделать все, что захотите, чтобы упростить синтаксис, но перед этим стоит ваша базовая реализация на стороне модели.

Если бы вы обрабатывали нажатие кнопки в вашем окне и увеличивали ViewModel.Trouble, вы бы увидели обновление в реальном времени в связанном элементе управления. Ура!

Осталось только подключить бизнес-уровень, т. Е. Сетевой уровень, к ViewModel. Вы можете сделать это любым количеством способов. Вы можете передать экземпляр модели представления на свой сетевой уровень, вы можете сделать так, чтобы модель представления напрямую реагировала на события на сетевом уровне - это действительно полностью зависит от вас.

Теперь, если вы продолжите и сделаете это, это не сработает. Сожалею. Теперь, это не полностью моя вина, вы видите, что Wpf не нравится, когда кто-то изменяет свои данные. Более конкретно, все, что может повлиять на элемент управления Wpf , должно быть вызвано в потоке Gui, который владеет элементом управления. Как вы можете догадаться, потоки, которые вы используете для изменения модели представления, происходят из сетевых прерываний и так далее. Сетевые темы. Pleabs. Морлоки . Тьфу !

Во всяком случае, я отвлекся. Есть относительно безболезненный способ обойти это. Когда вы обнаружите изменение, о котором вы хотите сообщить, отправьте изменение в ветку Gui.

someWpfControl.Dispatcher.Invoke (
    DispatcherPriority.Normal,
    new Action(
    delegate()
    {
        ViewModel.Trouble = someNewValue;
    });

но это отчасти бесполезно, так как ваш сетевой уровень не должен ничего знать о Wpf. Так как насчет ViewModel

...
// within property, after detecting change and 
// testing for listeners
someWpfControl.Dispatcher.Invoke (
    DispatcherPriority.Normal,
    new Action(
    delegate()
    {
        PropertyChanged (
            this, 
            new PropertyChangedEventArgs ("Trouble"));
    });
...

и так же, как и раньше, не стесняйтесь обернуть это где-нибудь еще. Как в вспомогательном методе. Кстати, «someWpfControl» может быть окном. Таким образом, вы можете передать его на Ctor. Я также настоятельно рекомендую вам альтернативы Google "вызывать Dispatcher", поскольку могут быть более умные способы сделать это, не включая контрольные ссылки, обширные вырезки и вставки в вашей модели представления или что-то подобное.

Пока поток графического интерфейса обновляет элемент управления, вы можете делать все, что захотите:)

Кроме того, бесстыдная вилка для моего приятеля и ученика Wpf Кента, который знает о Wpf бесконечно больше, чем я. [http://kentb.blogspot.com/]

Приветствия:)

...