コンソールアプリケーションをWPFに移植する
質問
C#で小さなチャットアプリケーションを作成し、コンソールアプリケーションとして開始しました。ただし、WPFを使用してGUIを作成します。これは、 InitializeConnection()
、 SendMessage(string msg)
などの関数を持つ DanMessengerClient
という名前のクラスです。
すでにVisual StudioでUIを設計しており、デフォルトでWindow1.xaml.csに Window1
クラスを作成しました。 " Send"のイベントハンドラーを作成しました。現在のところ、テキストエリアにダミーテキストのみを追加するボタン。私の質問は、 WINDow1クラスからSendMessage()関数を呼び出す方法
そのクラスでオブジェクトを作成しようとしましたが、最初のクラス内からテキストボックスにアクセスする必要があるため(つまり、メッセージを受信したときにテキストボックスを更新します)、Window1クラスへの参照を追加すると無限ループで参照を作成し続けるため、StackOverflow
例外。
GUIアプリケーションは初めてです。どうすればいいですか?
解決
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を実装する必要があることに注意してください。また、ユーザーがTextBoxを編集してもMessageTextプロパティが破壊されないように、OneWayバインディングに注意してください。 (TextBlockを使用して、ユーザーがまったく編集できないようにすることもできます。)
この設定が完了すると、WPFは_myMessenger.MessageTextプロパティの変更を自動的に監視し、発生時にTextBox.Textを更新します(つまり、メッセージの受信時)。
最後に、送信方法について:テキストを渡すだけです:
private void SendButton_Click(...)
{
_myMessenger.Send(MyTextBox.Text);
}
Name属性を使用して、送信するメッセージを含むテキストボックスに名前を付けます。
<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
を設定します。発信 TextBox
を MessageToSend
にバインドし、着信 TextBlock
を MessageBuffer
にバインドし、
。 SendMessage
を呼び出すボタン
テストオブジェクトに対してUIを動作させたら、同じインターフェイスを実装する別のクラスを作成します。このクラスのみが、プロパティセッターが相互運用するプライベート DanMessengerClient
オブジェクトを作成します。次に、代わりにウィンドウでこのオブジェクトのインスタンスを作成します。
実際のメッセージングクライアントは、おそらくより洗練されたものになる必要があります。たとえば、 LastMessageReceived
プロパティを実装して、そのテキストで特別なことを行うことができます。 ToolTip
。そして、 MessageBuffer
プロパティは実際には何らかの方法でリッチテキストをサポートする必要があるかもしれません。しかし、これは良い出発点です。