C# 将控制台应用程序移植到WPF

C# 将控制台应用程序移植到WPF,c#,.net,wpf,console,porting,C#,.net,Wpf,Console,Porting,我用C#创建了一个小型聊天应用程序,并以控制台应用程序开始。但是,我想使用WPF为它创建一个GUI。它是一个名为DanMessengerClient的类,具有InitializeConnection(),SendMessage(string msg)等函数 我已经在Visual Studio中设计了UI,它默认在Window1.xaml.cs上创建了Window1类。我为“Send”按钮创建了一个事件处理程序,到目前为止,它只向textarea添加一些伪文本。我的问题是,如何从WIndow1类调

我用C#创建了一个小型聊天应用程序,并以控制台应用程序开始。但是,我想使用WPF为它创建一个GUI。它是一个名为
DanMessengerClient
的类,具有
InitializeConnection()
SendMessage(string msg)
等函数

我已经在Visual Studio中设计了UI,它默认在Window1.xaml.cs上创建了
Window1
类。我为“Send”按钮创建了一个事件处理程序,到目前为止,它只向textarea添加一些伪文本。我的问题是,如何从WIndow1类调用SendMessage()函数?

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


我不熟悉GUI应用程序。如何继续?

WPF中显示数据的标准方法是将控件绑定到数据上(请参见MSDN中的)。这可能需要包装或重构messenger类,以便它公开可绑定属性。例如,messenger类可能会公开一个名为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}" />
注意:您的messenger类必须实现INotifyPropertyChanged才能工作。还要注意单向绑定,这样如果用户编辑文本框,它就不会破坏MessageText属性。(您也可以使用文本块,这样用户根本无法编辑它。)

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

最后,关于如何发送:只需传递文本:

private void SendButton_Click(...)
{
  _myMessenger.Send(MyTextBox.Text);
}
使用“名称”属性命名包含要发送的邮件的文本框:

<TextBox Name="MyTextBox" />

仅对itowlson所说的内容进行一点扩展:

我首先创建一个如下的界面:

interface IMessagingClient
{
    string MessageToSend { get; set; }
    string MessageBuffer { get; }
    void SendMessage();
}
实现这个接口的类的行为应该非常简单。当收到消息时,它会被添加到
MessageBuffer
(前面可能有一个换行符)。要发送消息,请设置
MessageToSend
并调用
SendMessage()
,这也会将发送的消息添加到
MessageBuffer
。为了保持简单,我跳过了很多实现细节

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

然后,我将代码添加到我的窗口以创建此类的实例,并将
DataContext
设置为该类。我会将我的出站
文本框
绑定到
消息发送
,将我的入站
文本块
绑定到
消息缓冲区
,并连接一个
按钮
调用
发送消息

一旦让UI针对我的测试对象工作,我将构建另一个实现相同接口的类,只有这个类将创建一个私有的
DanMessenger客户端
对象,属性设置器可以与之交互操作。然后我会让我的窗口创建这个对象的一个实例


实际的消息传递客户端可能需要更加复杂,例如,您可能希望实现一个
LastMessageReceived
属性,以便可以对该文本执行一些特殊的操作,例如将其放入
工具提示中。而
MessageBuffer
属性实际上可能需要以某种方式支持富文本。但是这是一个很好的起点。

这个类非常小,我对编辑它没有任何问题。然而,我不明白装订对我有什么帮助。你能给我举一个例子,说明如何使用它将字符串附加到文本框中吗?我假设你在类中已经有了代码,可以在收到消息时执行这些操作,对吗?因此,创建一个新属性,比如MessageText,最初是一个空字符串。现在,在接收代码中,将接收到的文本附加到MessageText,并引发MessageText的PropertyChanged事件。这就完成了对类的更改。现在在XAML中设置TextBox绑定和窗口DataContext,如上所示。现在,每当您的类更新MessageText时,WPF都会注意到PropertyChanged事件,并自动为您更新文本框。我将编辑以显示更多详细信息。好的,我已经更新了代码。请注意,我没有将字符串附加到文本框。我将它附加到数据模型中的一个属性,文本框自动地反映了这一点。这是一个惯用的WPF,避免了myMessenger需要引用Window1或文本框的问题。好吧,我明白了。但是,我应该在哪里初始化_myMessenger?如果我把它放在名称空间构造函数中,我会得到一个NullReferenceException,因为某种原因(我不知道为什么),我不确定“名称空间构造函数”是什么意思。在Window1实例构造函数中初始化它,如上面的片段所示。如果仍然获得NullReferenceException,则可以在调试器中单步执行,或检查堆栈跟踪,以了解发生此情况的原因。为什么需要类中的文本框?您的类应该只用于处理数据/给出结果,GUI只用于表示数据和结果。例如,在按钮处理程序中,您可以执行myMessengerClass.SendMessage(textBoxMessage.Text)。SendMessage方法应该知道如何处理收到的文本,即
interface IMessagingClient
{
    string MessageToSend { get; set; }
    string MessageBuffer { get; }
    void SendMessage();
}