2009-10-24 4 views
1

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

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

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

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

+1

Зачем вам текстовое поле внутри вашего класса? Ваш класс должен работать только для обработки данных/предоставления результатов, GUI только для представления датты и результата. Например, в вашем обработчике кнопок вы должны выполнить myMessengerClass.SendMessage (textBoxMessage.Text). Ваш метод SendMessage должен знать, что делать с полученным текстом, поэтому вам не нужно текстовое поле в вашем классе Messenger, а только его текст. – Carlo

ответ

3

Канонический путь в WPF для отображения данных заключается в привязке к нему элемента управления (см. Data Binding в MSDN). Это, вероятно, потребует, чтобы вы обменивали или рефакторировали свой класс мессенджера, чтобы он предоставлял свойства bindable. Например, ваш класс мессенджер может выставить свойство 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); 
} 

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

<TextBox Name="MyTextBox" /> 
+0

Класс очень маленький, у меня нет никаких проблем с его редактированием. Однако я не понимаю, как привязка может помочь мне. Не могли бы вы показать мне пример того, как добавить строку в текстовое поле, используя это? –

+0

Я предполагаю, что у вас уже есть код в классе, чтобы делать вещи, когда сообщение получено, не так ли? Поэтому создайте новое свойство, например MessageText, изначально пустую строку. Теперь в вашем коде получения добавьте полученный текст в MessageText и поднимите событие PropertyChanged для MessageText. Это завершает изменения класса. Теперь в вашем XAML вы установите привязку TextBox и ваше окно DataContext, как показано выше. Теперь, когда ваш класс обновляет MessageText, WPF заметит событие PropertyChanged и автоматически обновит TextBox для вас. Я отредактирую, чтобы показать более подробную информацию. – itowlson

+0

Хорошо, я обновил код. Обратите внимание, что я не добавляю строку в TextBox. Я добавляю его к свойству * в модели данных *, и текстовое поле автоматически отражает это. Это идиоматический WPF и обходит необходимость в _myMessenger иметь ссылку на Window1 или TextBox. – itowlson

0

Просто немного расширьте то, что говорит итолсон:

Я бы начал с создания такого интерфейса:

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 может действительно нуждаться в поддержке богатого текста в некотором роде. Но это хорошая отправная точка.