2009-10-24 70 views
1

我在C#中创建了一个小型聊天应用程序,并作为控制台应用程序启动。不过,我想用WPF为它创建一个GUI。这是一个与功能,如InitializeConnection()SendMessage(string msg)命名DanMessengerClient类等将控制台应用程序移植到WPF

我已经设计在Visual Studio的用户界面,它创造了它在默认情况下Window1.xaml.cs Window1类。我为“发送”按钮创建了一个事件处理程序,它只能将一些虚拟文本附加到textarea中。我的问题是,我应该如何从WIndow1类调用SendMessage()函数?

我尝试在该类中创建对象,但由于我还需要从第一个类内部访问文本框(即当我收到消息时,更新文本框),添加对Window1类的引用会引发StackOverflow异常,因为它不断在无限循环中创建引用。

我是新来的GUI应用程序。我应该如何继续?

+1

为什么你需要课堂内的文本框?你的课只应该用于处理数据/给出结果,图形用户界面仅用于表示数据和结果。例如在你的按钮处理程序中,你会做myMessengerClass.SendMessage(textBoxMessage.Text)。你的SendMessage方法应该知道如何处理接收到的文本,这样你就不需要信使类中的文本框,只需要它的文本。 – Carlo

回答

3

WPF中显示数据的规范方式是将控件绑定到它(请参阅MSDN中的Data Binding)。这可能需要你包装或重构你的信使类,以便它公开可绑定的属性。例如,你的信使类,就有可能暴露了一个名为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绑定,以便如果用户编辑文本框,则不会消除MessageText属性。 (您也可以使用TextBlock,以便用户根本无法编辑它。)

当您设置此设置后,WPF将自动监视_myMessenger.MessageText属性中的更改,并更新TextBox.Text发生时(即收到消息时)。

最后,关于如何做发送:只是通过文字:

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

使用name属性来命名包含消息的文本框中发送:

<TextBox Name="MyTextBox" /> 
+0

该类非常小,我没有任何编辑它的问题。不过,我不明白绑定如何帮助我。你能告诉我一个关于如何将字符串附加到文本框的例子吗? –

+0

我假设你已经有类中的代码来收到消息时做什么,对吧?所以创建一个新的属性,比如MessageText,最初是一个空字符串。现在,在您的接收代码中,将接收到的文本追加到MessageText中,并为MessageText引发PropertyChanged事件。这完成了对班级的更改。现在在您的XAML中,您设置了TextBox绑定和您的窗口DataContext,如上所示。现在,无论何时您的类更新MessageText,WPF都会注意到PropertyChanged事件并自动为您更新TextBox。我将编辑以显示更多细节。 – itowlson

+0

好的,我更新了代码。请注意,我没有将该字符串附加到TextBox。我将它附加到数据模型中的一个属性*,并且文本框自动反映了这一点。这是惯用的WPF,并且需要_myMessenger来引用Window1或TextBox。 – itowlson

0

只是为了扩大一下itowlson说什么:

我会开始创建一个这样的接口:

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

实现此接口的类的行为应该非常简单。收到消息时,它会被添加到MessageBuffer(可能前面有一个换行符)。要发送消息,请设置MessageToSend并呼叫SendMessage(),这也会将发送的消息添加到MessageBuffer。为了简单起见,我跳过了很多实现细节。

接下来,我会构建一个测试类,实现IMessagingClientINotifyPropertyChanged。这个类实际上并不需要做任何事情:它很可能只是随机产生随机测试消息并更新MessageBuffer;另外,当调用SendMessage时,它将清除MessageToSend和更新MessageBuffer

然后,我将代码添加到我的窗口来创建此类的实例并将DataContext设置为它。我会将我的外出TextBoxMessageToSend和我的入境TextBlockMessageBuffer,并挂钩Button以致电SendMessage

一旦我的UI对我的测试对象起作用,我会构建一个实现相同接口的类,只有这个类才会创建属性设置器互操作的私有对象DanMessengerClient。然后,我会让我的窗口创建此对象的一个​​实例。

实际的消息传递客户端可能需要更复杂一些,例如,您可能想要实现LastMessageReceived属性,以便您可以对该文本执行一些特殊的操作,例如将它放在ToolTip中。并且MessageBuffer属性可能实际上需要以某种方式支持富文本。但这是一个很好的起点。

相关问题