下面我们来接着做客户端:
1.在Solution中添加SiliverLight Project,命名为ChatClient
这里,我将对应的网站 放在WCF Service中
2.先在ChatClient工程中 添加DLL引用:
System.Runtime.Serialization.dll
System.ServiceModel.dll
System.ServiceModel.PollingDuplex.dll
3.先绘制一个简单界面,修改Page.xaml 如下:
4.在相应的 Page.xaml.cs中 添加如下引用:
5.添加如下代码,创建Channel
6.加如相应的完成事件
注意:
(1)这里的
(2)利用
IDuplexSessionChannel.BeginSend()方法 与服务器通信
7.完成与服务器通信的相应调用
8.加入前台逻辑处理
***********************************华丽的分割线**************************************
至此 一个支持回调的SiliverLight 2.0 聊天室 就完成了,从中间可以看出,SiliverLight对WCF的支持还是不够好,
它并不能连接TCP的WCF Service Host 这样,它所支持的所谓CallBack实际上 是SiliverLight内部自己的轮询,
在本质上,似乎还是没有什么重大的突破,只是做的更有效率一点而已,但是SiliverLight所支持的多线程操作,
使其有更好的可发展空间,这一点,也是让大家十分高兴的~毕竟不会象原来那样,因为种种原因,整个浏览器崩掉~
*****************************
应要求 现在补上我的Sulotion : Download
1.在Solution中添加SiliverLight Project,命名为ChatClient
这里,我将对应的网站 放在WCF Service中
2.先在ChatClient工程中 添加DLL引用:
System.Runtime.Serialization.dll
System.ServiceModel.dll
System.ServiceModel.PollingDuplex.dll
3.先绘制一个简单界面,修改Page.xaml 如下:
<UserControl x:Class="ChatClient.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="655" Height="420">
<Grid x:Name="LayoutRoot"
Background="White"
ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid ShowGridLines="True"
Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<!--聊天内容-->
<!--TODO:加入滚动条-->
<TextBlock x:Name="txt_CharText"
Grid.Column="0"
Grid.Row="0"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
<!--用户列表-->
<!--TODO:加入滚动条 ListView-->
<TextBlock x:Name="txt_lstChatters"
Grid.Column="1"
VerticalAlignment="Top"
HorizontalAlignment="Center" />
</Grid>
<Grid Grid.Row="1"
ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="75" />
<ColumnDefinition Width="150" />
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<!--输入对话框-->
<TextBox x:Name="tb_Message"
Grid.Column="0"
Margin="5,5,5,5"
KeyDown="tb_Message_KeyDown"/>
<!--发送按钮-->
<Button x:Name="btn_Say"
Grid.Column="1"
Width="70"
Height="30"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Click="btn_Say_Click">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center">Send</TextBlock></Button>
<!--名字输入对话框-->
<TextBox x:Name="tb_Name"
Grid.Column="2"
Margin="5,5,5,5"
Text="Guest"
KeyDown="tb_Name_KeyDown"/>
<!--Connect按钮-->
<Button x:Name="btn_Connect"
Grid.Column="3"
Width="70"
Height="30"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Click="btn_Connect_Click">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center">Connect</TextBlock>
</Button>
</Grid>
</Grid>
</UserControl>
为了方便用户输入,在两个TextBox中 加入了KeyDown事件 用来截获"回车"符xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="655" Height="420">
<Grid x:Name="LayoutRoot"
Background="White"
ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid ShowGridLines="True"
Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<!--聊天内容-->
<!--TODO:加入滚动条-->
<TextBlock x:Name="txt_CharText"
Grid.Column="0"
Grid.Row="0"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
<!--用户列表-->
<!--TODO:加入滚动条 ListView-->
<TextBlock x:Name="txt_lstChatters"
Grid.Column="1"
VerticalAlignment="Top"
HorizontalAlignment="Center" />
</Grid>
<Grid Grid.Row="1"
ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="75" />
<ColumnDefinition Width="150" />
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<!--输入对话框-->
<TextBox x:Name="tb_Message"
Grid.Column="0"
Margin="5,5,5,5"
KeyDown="tb_Message_KeyDown"/>
<!--发送按钮-->
<Button x:Name="btn_Say"
Grid.Column="1"
Width="70"
Height="30"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Click="btn_Say_Click">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center">Send</TextBlock></Button>
<!--名字输入对话框-->
<TextBox x:Name="tb_Name"
Grid.Column="2"
Margin="5,5,5,5"
Text="Guest"
KeyDown="tb_Name_KeyDown"/>
<!--Connect按钮-->
<Button x:Name="btn_Connect"
Grid.Column="3"
Width="70"
Height="30"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Click="btn_Connect_Click">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center">Connect</TextBlock>
</Button>
</Grid>
</Grid>
</UserControl>
4.在相应的 Page.xaml.cs中 添加如下引用:
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Threading;
using System.ServiceModel.Channels;
using System.Threading;
5.添加如下代码,创建Channel
SynchronizationContext uiThread;
IDuplexSessionChannel m_Channel;
public void InitChannel()
{
// Grab a reference to the UI thread.
uiThread = SynchronizationContext.Current;
uiThread.Post(WriteText, "Connecting" + Environment.NewLine);
// Instantiate the binding and set the time-outs.
PollingDuplexHttpBinding binding = new PollingDuplexHttpBinding()
{
PollTimeout = TimeSpan.FromSeconds(10),
InactivityTimeout = TimeSpan.FromMinutes(1)
};
// Instantiate and open channel factory from binding.
IChannelFactory<IDuplexSessionChannel> factory =
binding.BuildChannelFactory<IDuplexSessionChannel>(new BindingParameterCollection());
IAsyncResult factoryOpenResult =
factory.BeginOpen(new AsyncCallback(OnOpenCompleteFactory), factory);
if (factoryOpenResult.CompletedSynchronously)
{
CompleteOpenFactory(factoryOpenResult);
}
}
这里利用IDuplexSessionChannel m_Channel;
public void InitChannel()
{
// Grab a reference to the UI thread.
uiThread = SynchronizationContext.Current;
uiThread.Post(WriteText, "Connecting" + Environment.NewLine);
// Instantiate the binding and set the time-outs.
PollingDuplexHttpBinding binding = new PollingDuplexHttpBinding()
{
PollTimeout = TimeSpan.FromSeconds(10),
InactivityTimeout = TimeSpan.FromMinutes(1)
};
// Instantiate and open channel factory from binding.
IChannelFactory<IDuplexSessionChannel> factory =
binding.BuildChannelFactory<IDuplexSessionChannel>(new BindingParameterCollection());
IAsyncResult factoryOpenResult =
factory.BeginOpen(new AsyncCallback(OnOpenCompleteFactory), factory);
if (factoryOpenResult.CompletedSynchronously)
{
CompleteOpenFactory(factoryOpenResult);
}
}
SynchronizationContext.Current.Post()
异步向页面输送信息6.加如相应的完成事件
void OnOpenCompleteFactory(IAsyncResult result)
{
if (result.CompletedSynchronously)
return;
else
CompleteOpenFactory(result);
}
void CompleteOpenFactory(IAsyncResult result)
{
IChannelFactory<IDuplexSessionChannel> factory =
(IChannelFactory<IDuplexSessionChannel>)result.AsyncState;
factory.EndOpen(result);
// The factory is now open. Create and open a channel from the channel factory.
IDuplexSessionChannel channel =
factory.CreateChannel(new EndpointAddress("http://192.168.0.13:18600/ChatService.svc"));
IAsyncResult channelOpenResult =
channel.BeginOpen(new AsyncCallback(OnOpenCompleteChannel), channel);
if (channelOpenResult.CompletedSynchronously)
{
CompleteOpenChannel(channelOpenResult);
}
}
void OnOpenCompleteChannel(IAsyncResult result)
{
if (result.CompletedSynchronously)
return;
else
CompleteOpenChannel(result);
}
void CompleteOpenChannel(IAsyncResult result)
{
IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
channel.EndOpen(result);
this.m_Channel = channel;
// The channel is now open. Send a message.
Message message = Message.CreateMessage(channel.GetProperty<MessageVersion>(), "Silverlight/IChat/JoinChat", this.tb_Name.Text.ToString());
IAsyncResult resultChannel = channel.BeginSend(message, new AsyncCallback(OnSend), channel);
if (resultChannel.CompletedSynchronously)
{
CompleteOnSend(resultChannel);
}
// Also start the receive loop to listen for callbacks from the service.
ReceiveLoop(channel);
}
{
if (result.CompletedSynchronously)
return;
else
CompleteOpenFactory(result);
}
void CompleteOpenFactory(IAsyncResult result)
{
IChannelFactory<IDuplexSessionChannel> factory =
(IChannelFactory<IDuplexSessionChannel>)result.AsyncState;
factory.EndOpen(result);
// The factory is now open. Create and open a channel from the channel factory.
IDuplexSessionChannel channel =
factory.CreateChannel(new EndpointAddress("http://192.168.0.13:18600/ChatService.svc"));
IAsyncResult channelOpenResult =
channel.BeginOpen(new AsyncCallback(OnOpenCompleteChannel), channel);
if (channelOpenResult.CompletedSynchronously)
{
CompleteOpenChannel(channelOpenResult);
}
}
void OnOpenCompleteChannel(IAsyncResult result)
{
if (result.CompletedSynchronously)
return;
else
CompleteOpenChannel(result);
}
void CompleteOpenChannel(IAsyncResult result)
{
IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
channel.EndOpen(result);
this.m_Channel = channel;
// The channel is now open. Send a message.
Message message = Message.CreateMessage(channel.GetProperty<MessageVersion>(), "Silverlight/IChat/JoinChat", this.tb_Name.Text.ToString());
IAsyncResult resultChannel = channel.BeginSend(message, new AsyncCallback(OnSend), channel);
if (resultChannel.CompletedSynchronously)
{
CompleteOnSend(resultChannel);
}
// Also start the receive loop to listen for callbacks from the service.
ReceiveLoop(channel);
}
注意:
(1)这里的
IDuplexSessionChannel channel =
factory.CreateChannel(new EndpointAddress("http://192.168.0.13:18600/ChatService.svc"));
这个地址应该添入,WCF Service的地址,不要忘记端口号factory.CreateChannel(new EndpointAddress("http://192.168.0.13:18600/ChatService.svc"));
(2)利用
IDuplexSessionChannel.BeginSend()方法 与服务器通信
7.完成与服务器通信的相应调用
void OnSend(IAsyncResult result)
{
if (result.CompletedSynchronously)
return;
else
CompleteOnSend(result);
}
void CompleteOnSend(IAsyncResult result)
{
IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
channel.EndSend(result);
}
void ReceiveLoop(IDuplexSessionChannel channel)
{
// Start listening for callbacks.
IAsyncResult result = channel.BeginReceive(new AsyncCallback(OnReceiveComplete), channel);
if (result.CompletedSynchronously)
CompleteReceive(result);
}
void OnReceiveComplete(IAsyncResult result)
{
if (result.CompletedSynchronously)
return;
else
CompleteReceive(result);
}
void CompleteReceive(IAsyncResult result)
{
// A callback was received.
IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
try
{
Message receivedMessage = channel.EndReceive(result);
if (receivedMessage == null)
{
// Server closed its output session, can close client channel,
// or continue sending messages to start a new session.
}
else
{
// Show the service response in the UI.
string text = receivedMessage.GetBody<string>();
uiThread.Post(WriteText, text + Environment.NewLine);
ReceiveLoop(channel);
}
}
catch (CommunicationObjectFaultedException)
{
// The channel inactivity time-out was reached.
}
}
private void SendMessage(string text)
{
// The channel is now open. Send a message
Message message = Message.CreateMessage(this.m_Channel.GetProperty<MessageVersion>(), "Silverlight/IChat/SayChat", text);
IAsyncResult resultChannel = this.m_Channel.BeginSend(message, new AsyncCallback(OnSend), this.m_Channel);
if (resultChannel.CompletedSynchronously)
{
CompleteOnSend(resultChannel);
}
// Also start the receive loop to listen for callbacks from the service.
ReceiveLoop(this.m_Channel);
}
{
if (result.CompletedSynchronously)
return;
else
CompleteOnSend(result);
}
void CompleteOnSend(IAsyncResult result)
{
IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
channel.EndSend(result);
}
void ReceiveLoop(IDuplexSessionChannel channel)
{
// Start listening for callbacks.
IAsyncResult result = channel.BeginReceive(new AsyncCallback(OnReceiveComplete), channel);
if (result.CompletedSynchronously)
CompleteReceive(result);
}
void OnReceiveComplete(IAsyncResult result)
{
if (result.CompletedSynchronously)
return;
else
CompleteReceive(result);
}
void CompleteReceive(IAsyncResult result)
{
// A callback was received.
IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
try
{
Message receivedMessage = channel.EndReceive(result);
if (receivedMessage == null)
{
// Server closed its output session, can close client channel,
// or continue sending messages to start a new session.
}
else
{
// Show the service response in the UI.
string text = receivedMessage.GetBody<string>();
uiThread.Post(WriteText, text + Environment.NewLine);
ReceiveLoop(channel);
}
}
catch (CommunicationObjectFaultedException)
{
// The channel inactivity time-out was reached.
}
}
private void SendMessage(string text)
{
// The channel is now open. Send a message
Message message = Message.CreateMessage(this.m_Channel.GetProperty<MessageVersion>(), "Silverlight/IChat/SayChat", text);
IAsyncResult resultChannel = this.m_Channel.BeginSend(message, new AsyncCallback(OnSend), this.m_Channel);
if (resultChannel.CompletedSynchronously)
{
CompleteOnSend(resultChannel);
}
// Also start the receive loop to listen for callbacks from the service.
ReceiveLoop(this.m_Channel);
}
8.加入前台逻辑处理
private void btn_Say_Click(object sender, RoutedEventArgs e)
{
SendMessage(this.tb_Message.Text.ToString());
this.tb_Message.Text = "";
}
private void btn_Connect_Click(object sender, RoutedEventArgs e)
{
InitChannel();
}
private void tb_Message_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
SendMessage(this.tb_Message.Text.ToString());
this.tb_Message.Text = "";
}
}
private void tb_Name_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
InitChannel();
}
}
void WriteText(object text)
{
this.txt_CharText.Text += (string)text;
}
{
SendMessage(this.tb_Message.Text.ToString());
this.tb_Message.Text = "";
}
private void btn_Connect_Click(object sender, RoutedEventArgs e)
{
InitChannel();
}
private void tb_Message_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
SendMessage(this.tb_Message.Text.ToString());
this.tb_Message.Text = "";
}
}
private void tb_Name_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
InitChannel();
}
}
void WriteText(object text)
{
this.txt_CharText.Text += (string)text;
}
***********************************华丽的分割线**************************************
至此 一个支持回调的SiliverLight 2.0 聊天室 就完成了,从中间可以看出,SiliverLight对WCF的支持还是不够好,
它并不能连接TCP的WCF Service Host 这样,它所支持的所谓CallBack实际上 是SiliverLight内部自己的轮询,
在本质上,似乎还是没有什么重大的突破,只是做的更有效率一点而已,但是SiliverLight所支持的多线程操作,
使其有更好的可发展空间,这一点,也是让大家十分高兴的~毕竟不会象原来那样,因为种种原因,整个浏览器崩掉~
*****************************
应要求 现在补上我的Sulotion : Download