简体   繁体   English

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

[英]Porting a console application to WPF

I have created a small chatting application in C#, and started as a Console Application. 我已经用C#创建了一个小型的聊天应用程序,并开始作为一个控制台应用程序。 However I want to create a GUI for it using WPF. 但是我想使用WPF为它创建一个GUI。 It's a class named DanMessengerClient with functions such as InitializeConnection() , SendMessage(string msg) , etc. 这是一个名为DanMessengerClient的类,具有诸如InitializeConnection()SendMessage(string msg)等功能。

I have already designed the UI in Visual Studio, and it created it's Window1 class on Window1.xaml.cs by default. 我已经在Visual Studio中设计了UI,并且默认情况下它在Window1上创建了Window1类。 I created an event handler for the "Send" button that only appends some dummy text to a textarea as of now. 到目前为止,我为“发送”按钮创建了一个事件处理程序,该处理程序仅将一些虚拟文本附加到文本区域。 My question is, how should I call the SendMessage() function from the WIndow1 class? 我的问题是, 我应该如何从WIndow1类中调用SendMessage()函数?

I tried creating the object in that class, but since I also need to access the Textbox from inside the first class (ie When I recieve a message, update the textbox), adding the reference to the Window1 class throws a StackOverflow exception because it keeps creating references in an infinite loop. 我尝试在该类中创建对象,但是由于我还需要从第一个类内部访问Textbox(即,当我收到消息时,更新文本框),因此对Window1类的引用添加会引发StackOverflow异常,因为它会在无限循环中创建引用。

I'm new to GUI applications. 我是GUI应用程序的新手。 How should I proceed? 我应该如何进行?

The canonical way in WPF to display data is to bind a control to it (see Data Binding in MSDN). WPF中显示数据的规范方法是将控件绑定到该控件(请参阅MSDN中的数据绑定 )。 This would probably require that you wrap or refactor your messenger class so that it exposes bindable properties. 这可能需要包装或重构Messenger类,以便它公开可绑定的属性。 For example, your messenger class might expose a property called MessageText, which you update every time you receive a message: 例如,您的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;
}

Now you would bind the TextBox.Text property to this new property: 现在,您将TextBox.Text属性绑定到此新属性:

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

This assumes that the messenger object is set as the window's DataContext, eg when the window creates the messenger: 假定将Messenger对象设置为窗口的DataContext,例如,当窗口创建Messenger时:

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

Note your messenger class must implement INotifyPropertyChanged for this to work. 请注意,您的Messenger类别必须实现INotifyPropertyChanged才能起作用。 Also note the OneWay binding so that if the user edits the TextBox it doesn't muck up the MessageText property. 还要注意OneWay绑定,这样,如果用户编辑TextBox,它就不会破坏MessageText属性。 (You could also use a TextBlock, so that the user couldn't edit it at all.) (您也可以使用TextBlock,以便用户完全无法编辑它。)

When you've got this set up, WPF will automatically monitor for changes in the _myMessenger.MessageText property, and update the TextBox.Text as they happen (ie as messages are received). 完成此设置后,WPF将自动监视_myMessenger.MessageText属性中的更改,并在发生更改时(即,在收到消息时)更新TextBox.Text。

Finally, regarding how to do the send: just pass the text: 最后,关于如何发送:只需传递文本即可:

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

Use the Name attribute to name the text box containing the message to be sent: 使用“名称”属性为包含要发送的消息的文本框命名:

<TextBox Name="MyTextBox" />

Just to expand a bit on what itowlson is saying: 只是为了扩展一下itowlson所说的话:

I'd start by creating an interface like this: 我将从创建这样的接口开始:

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

The behavior of classes implementing this interface should be pretty simple. 实现此接口的类的行为应该非常简单。 When a message is received, it gets added to MessageBuffer (probably preceded by a newline). 收到消息后,它将被添加到MessageBuffer (可能在换行符之后)。 To send a message, set MessageToSend and call SendMessage() , which also adds the sent message to MessageBuffer . 要发送消息,请设置MessageToSend并调用SendMessage() ,这还将发送的消息添加到MessageBuffer There are a lot of implementation details I'm skipping to keep this simple. 为了简化起见,我跳过了很多实现细节。

Next, I'd build a test class that implemented IMessagingClient and INotifyPropertyChanged . 接下来,我将构建一个实现IMessagingClientINotifyPropertyChanged的测试类。 This class doesn't actually have to do anything real: it would most likely just produce random test messages at random intervals and update MessageBuffer ; 此类实际上不需要做任何实际的事情:它很可能仅以随机间隔生成随机测试消息并更新MessageBuffer also, when SendMessage is called, it would clear MessageToSend and update MessageBuffer . 同样,在调用SendMessage时,它将清除MessageToSend并更新MessageBuffer

I'd then add code to my window to create an instance of this class and set the DataContext to it. 然后,将代码添加到窗口中以创建此类的实例并将DataContext设置为该实例。 I'd bind my outbound TextBox to MessageToSend and my inbound TextBlock to MessageBuffer , and hook up a Button to call SendMessage . 我将出站TextBox绑定到MessageToSend ,将入站TextBlock绑定到MessageBuffer ,并连接一个Button来调用SendMessage

Once I got the UI working against my test object, I'd build a another class that implemented the same interfaces, only this one would create a private DanMessengerClient object that the property setters interoperated with. 一旦使UI与测试对象配合使用,我将构建另一个实现相同接口的类,只有该类才能创建一个私有的DanMessengerClient对象,该属性与设置程序进行交互。 Then I'd make my window create an instance of this object instead. 然后,我将使窗口创建该对象的实例。

An actual messaging client is probably going to need to be more sophisticated, For instance, you might want to implement a LastMessageReceived property so that you can do something special with that text, like put it in a ToolTip . 实际的消息传递客户端可能需要更复杂,例如,您可能想要实现LastMessageReceived属性,以便可以对该文本执行一些特殊的操作,例如将其放入ToolTip And the MessageBuffer property might actually need to support rich text in some way. 而且, MessageBuffer属性实际上可能需要以某种方式支持富文本格式。 But this is a good starting point. 但这是一个很好的起点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM