Портирование консольного приложения в WPF - PullRequest
1 голос
/ 25 октября 2009

Я создал небольшое приложение для чата в C # и запустил его как консольное приложение. Однако я хочу создать графический интерфейс для него с помощью WPF. Это класс с именем DanMessengerClient с такими функциями, как InitializeConnection(), SendMessage(string msg) и т. Д.

Я уже спроектировал пользовательский интерфейс в Visual Studio, и он создал класс Window1 в Window1.xaml.cs по умолчанию. Я создал обработчик событий для кнопки «Отправить», который на данный момент добавляет к текстовой области только фиктивный текст. У меня вопрос, как мне вызвать функцию SendMessage () из класса WIndow1?

Я попытался создать объект в этом классе, но так как мне также нужно получить доступ к Textbox из первого класса (т. Е. Когда я получаю сообщение, обновите текстовое поле), добавление ссылки на класс Window1 выдает StackOverflow исключение, потому что он продолжает создавать ссылки в бесконечном цикле.

Я новичок в приложениях с графическим интерфейсом. Как мне поступить?

Ответы [ 2 ]

3 голосов
/ 25 октября 2009

Канонический способ отображения данных в WPF - привязать к нему элемент управления (см. Привязка данных в MSDN). Это, вероятно, потребует, чтобы вы обернули или реорганизовали свой класс мессенджера, чтобы он предоставил привязываемые свойства. Например, ваш класс мессенджера может предоставлять свойство MessageText, которое вы обновляете каждый раз, когда получаете сообщение:

// INotifyPropertyChanged interface implementation and plumbing

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged(string propertyName)
{
  if (PropertyChanged != null)
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName);
}

// The property you are going to bind to

private string _messageText = String.Empty;

public string MessageText
{
  get { return _messageText; }
  set
  {
    _messageText = value;
    OnPropertyChanged("MessageText");
  }
}

// How to modify your code to update the bindable property

private void OnMessageReceive(string message) // assuming this method already exists
{
  MessageText = MessageText + Environment.NewLine + message;
}

Теперь вы бы привязали свойство TextBox.Text к этому новому свойству:

<TextBox Text="{Binding MessageText, Mode=OneWay}" />

Это предполагает, что объект мессенджера установлен как DataContext окна, например когда окно создает мессенджер:

public class Window1()
{
  _myMessenger =  = new DanMessengerClient();
  this.DataContext = _myMessenger;
}

Обратите внимание, что ваш класс мессенджера должен реализовывать INotifyPropertyChanged, чтобы это работало. Также обратите внимание на привязку OneWay, так что если пользователь редактирует TextBox, он не портит свойство MessageText. (Вы также можете использовать TextBlock, чтобы пользователь вообще не мог его редактировать.)

Когда вы настроите эту настройку, WPF будет автоматически отслеживать изменения в свойстве _myMessenger.MessageText и обновлять TextBox.Text по мере их появления (т.е. при получении сообщений).

Наконец, что касается отправки: просто передайте текст:

private void SendButton_Click(...)
{
  _myMessenger.Send(MyTextBox.Text);
}

Используйте атрибут Name, чтобы присвоить имя текстовому полю, содержащему сообщение для отправки:

<TextBox Name="MyTextBox" />
0 голосов
/ 25 октября 2009

Просто немного подробнее о том, что говорит Итоулсон:

Я бы начал с создания интерфейса, подобного этому:

interface IMessagingClient
{
    string MessageToSend { get; set; }
    string MessageBuffer { get; }
    void SendMessage();
}

Поведение классов, реализующих этот интерфейс, должно быть довольно простым. Когда сообщение получено, оно добавляется к MessageBuffer (вероятно, с новой строкой). Чтобы отправить сообщение, установите MessageToSend и позвоните SendMessage(), что также добавляет отправленное сообщение к MessageBuffer. Есть много деталей реализации, которые я пропускаю, чтобы сохранить это простым.

Далее я бы создал тестовый класс, в котором реализованы IMessagingClient и INotifyPropertyChanged. Этот класс на самом деле не должен делать ничего реального: он, скорее всего, будет просто генерировать случайные тестовые сообщения с произвольными интервалами и обновлять MessageBuffer; также, когда вызывается SendMessage, он очищает MessageToSend и обновляет MessageBuffer.

Затем я добавил бы код в свое окно, чтобы создать экземпляр этого класса и установить для него DataContext. Я бы связал свой исходящий TextBox с MessageToSend и мой входящий TextBlock с MessageBuffer и подключил бы Button для вызова SendMessage.

После того как пользовательский интерфейс работал с моим тестовым объектом, я бы создал другой класс, который реализовывал те же интерфейсы, только этот создаст частный объект DanMessengerClient, с которым взаимодействуют установщики свойств. Тогда я бы заставил мое окно создать экземпляр этого объекта.

Реальный клиент обмена сообщениями, вероятно, должен быть более сложным. Например, вы можете захотеть реализовать свойство LastMessageReceived, чтобы вы могли сделать что-то особенное с этим текстом, например, поместить его в ToolTip. А свойство MessageBuffer может на самом деле должно каким-то образом поддерживать форматированный текст. Но это хорошая отправная точка.

...