UWP开发之StreamSocket聊天室(五)

Cle****-he UID.1073626
2015-11-17 发表

本帖最后由 entty 于 2015-11-19 00:50 编辑

这篇文章是"UWP开发之StreamSocket聊天室"系列的最后一篇文章,这篇文章中我们来实现聊天室服务端View的实现。

由于很多View 、ViewModel和客户端的是基本一致的所以本篇内容会比较少,很多技术重合点这里也不会再做讲解。

其实在日常的开发中我们的服务端不应该是以UWP形式来开发的,通常情况下是在服务器使用Socket技术来搭建一个IM服务端,我们这里仅仅是为了探索StreamSocket Service在UWP上如何使用才如此去做。

首先我们还是先看设置界面的Xaml布局


SettingPage

Pages/SettingPage.xaml

[mw_shl_code=csharp,true]<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Margin="8">
<TextBlock>
<Run Text="本机IP地址:"/>
<Run Text="{x:Bind _vm.LocalHostName}"/>
<LineBreak/>
<Run Text="端口:"/>
<Run Text="{x:Bind _vm.LocalServiceName}"/>
</TextBlock>
<ToggleSwitch x:Name="SocketSwitch" IsOn="{x:Bind _vm.SocketState,Mode = TwoWay}" Toggled="{x:Bind ListenSocket}" Header="开启服务" />
</StackPanel>
</Grid>[/mw_shl_code]


放上一个TextBlock来显示本机IP和服务开放的端口号,然后用ToggleSwitch来控制服务的开启与关闭,其中ToggleSwitch控件的Toggled事件绑定到了后端的ListenSocket方法上。

来看看后端代码Pages/SettingPage.xaml.cs

[mw_shl_code=csharp,true]public sealed partial class SettingPage : Page
{
private readonly SettingViewModel _vm = ViewModelLocator.Default.SettingViewModel;

public SettingPage()
{
InitializeComponent();
}

private void ListenSocket()
{
if (SocketSwitch.IsOn)
{
_vm.ServerSocket.Start();
}
else
{
_vm.ServerSocket.Dispose();
}
}
}[/mw_shl_code]


后台代码也很简单,ListenSocket方法根据SocketSwitch的闭合去决定是开启服务还是关闭服务。开启和关闭服务的具体操作在该界面对应的SettingViewModel中。

看下该界面的ViewModel是什么样子的

ViewModel/SettingViewModel.cs

[mw_shl_code=csharp,true]public class SettingViewModel : ViewModelBase
{
public UserModel UserModel { get; set; } = new UserModel {UserName = "服务器"};

/// <summary>
/// Socket服务端
/// </summary>
public SocketBase ServerSocket { get; set; }

/// <summary>
/// 监听状态文本描述
/// </summary>
public string ListeningStateTxt { get; set; }

/// <summary>
/// 监听TCP链接的端口号
/// </summary>
public string LocalServiceName { get; set; }

/// <summary>
/// 本地IP
/// </summary>
public string LocalHostName { get; set; }

/// <summary>
/// 是否已开启 Socket 服务
/// </summary>
public bool SocketState { get; set; }

/// <summary>
/// 消息集合
/// </summary>
public ObservableCollection<MessageModel> MessageCollection { get; set; } =
new ObservableCollection<MessageModel>();

public SettingViewModel()
{
LocalHostName = GetLocalIp();
LocalServiceName = "22233";

//创建服务端Socket
//(方法名忘记改了 就这样吧 CreatInkSocket 是创建Ink墨迹的服务端,前段时间做的Ink墨迹同步。大家如果看着不爽就自行改吧)
ServerSocket = SocketFactory.CreatInkSocket(true, LocalHostName, LocalServiceName);
//新消息到达通知
ServerSocket.MsgReceivedAction += data =>
{
DispatcherHelper.CheckBeginInvokeOnUI(() => { MessageCollection.Add(data); });
Messenger.Default.Send(data, "NewMsgAction");
};
}

/// <summary>
/// 获取本地ip地址
/// </summary>
/// <returns>ip</returns>
private string GetLocalIp()
{
var icp = NetworkInformation.GetInternetConnectionProfile();

if (icp?.NetworkAdapter == null) return null;
var hostname =
NetworkInformation.GetHostNames()
.SingleOrDefault(
hn =>
hn.IPInformation?.NetworkAdapter != null && hn.IPInformation.NetworkAdapter.NetworkAdapterId
== icp.NetworkAdapter.NetworkAdapterId);

// the ip address
return hostname?.CanonicalName;
}
}[/mw_shl_code]

Ok,配置界面的工作到此就完成了


MessagePage

来看看MessagePage的UI以及后台代码,和客户端的也是一毛一样的,还是贴一下代码吧,代码就不解释了,想要了解的可以看这篇文章:UWP开发之StreamSocket聊天室(四)

Pages/MessagePage.xaml

[mw_shl_code=csharp,true]<Page.Resources>
<DataTemplate x:Key="OtherMsgDataTemplate" x:DataType="model:MessageModel">
<Grid Margin="0,8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Foreground="Red" VerticalAlignment="Center" >
<Run Text="{x:Bind User.UserName}"/>
<Run Text=": "/>
<Run Text="{x:Bind SetDateTime}"/>
</TextBlock>
<Grid Grid.Row="1">
<Border Margin="24,0" Padding="16,4" Background="White" CornerRadius="12" HorizontalAlignment="Left" >
<TextBlock TextWrapping="Wrap" Text="{x:Bind Message}"/>
</Border>
<Viewbox HorizontalAlignment="Left" Margin="16,0,0,0" Height="19" VerticalAlignment="Top" Width="13.5">
<Path Data="M32.4762,3.74901 C28.1542,4.60015 20.7241,2.92959 13.75,0.75 C15.5005,7.13589 28.4124,17.9116 29.5357,17.4874" Fill="White" Stretch="Fill" Stroke="White" UseLayoutRounding="False" d:LayoutOverrides="VerticalAlignment" />
</Viewbox>
</Grid>

</Grid>
</DataTemplate>
<DataTemplate x:Key="MyMsgDataTemplate" x:DataType="model:MessageModel">
<Grid Margin="0,8" HorizontalAlignment="Right">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Right" Foreground="Blue" >
<Run/>
<Run Text="{x:Bind SetDateTime}"/>
</TextBlock>
<Grid Grid.Row="1">
<Border Margin="24,0" Padding="16,4" Background="White" CornerRadius="12" HorizontalAlignment="Right" >
<TextBlock TextWrapping="Wrap" Text="{x:Bind Message}"/>
</Border>
<Viewbox HorizontalAlignment="Right" Margin="16,0" Height="19" VerticalAlignment="Top" Width="13.5" RenderTransformOrigin="0.5,0.5">
<Viewbox.RenderTransform>
<CompositeTransform ScaleX="-1"/>
</Viewbox.RenderTransform>
<Path Data="M32.4762,3.74901 C28.1542,4.60015 20.7241,2.92959 13.75,0.75 C15.5005,7.13589 28.4124,17.9116 29.5357,17.4874" Fill="White" Stretch="Fill" Stroke="White" UseLayoutRounding="False" d:LayoutOverrides="VerticalAlignment" />
</Viewbox>
</Grid>
</Grid>
</DataTemplate>
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListView x:Name="MsgListView" Background="#FFE6E6E6" ItemsSource="{x:Bind _vm.MessageCollection}" SelectionMode="None" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplateSelector>
<toolkit:MsgStyleSelector MyMsgStyle="{StaticResource MyMsgDataTemplate}" OtherMsgStyle="{StaticResource OtherMsgDataTemplate}" />
</ListView.ItemTemplateSelector>
</ListView>
<Grid Margin="0,8" Grid.Row="1">
<StackPanel>
<TextBox Text="{x:Bind _vm.TxtMsg,Mode= TwoWay}" KeyDown="{x:Bind _vm.MsgTextBoxKeyUp}" />
<Button Margin="0,4" Content="发送" HorizontalAlignment="Right" Click="{x:Bind _vm.SendTxtMsg}" VerticalAlignment="Bottom"/>
</StackPanel>
</Grid>
</Grid>
</Grid>[/mw_shl_code]

后台代码:

[mw_shl_code=csharp,true]public sealed partial class MessagePage : Page
{
private MessageViewModel _vm = ViewModelLocator.Default.MessageViewModel;

public MessagePage()
{
InitializeComponent();
}

private async void SendedMsgAction(MessageModel obj)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
MsgListView.ScrollIntoView(obj);
});
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
Messenger.Default.Register<MessageModel>(this, "NewMsgAction", SendedMsgAction);
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
Messenger.Default.Unregister(this);
}
}[/mw_shl_code]



来看下该界面的ViewModel,ViewModel中的工作也和客户端的ViewModel工作一样:

[mw_shl_code=csharp,true]public class MessageViewModel : ViewModelBase
{
private string _txtMsg;

/// <summary>
/// 要发送的文本
/// </summary>
public string TxtMsg
{
get { return _txtMsg; }
set
{
_txtMsg = value;
RaisePropertyChanged();
}
}

/// <summary>
/// 消息集合
/// </summary>
public ObservableCollection<MessageModel> MessageCollection { get; } =
ViewModelLocator.Default.SettingViewModel.MessageCollection;


/// <summary>
/// 发送消息
/// </summary>
/// <returns></returns>
public async Task SendTxtMsg()
{
if (string.IsNullOrEmpty(TxtMsg)) return;
var msg = new MessageModel
{
MessageType = MessageType.TextMessage,
Message = TxtMsg,
SetDateTime = DateTime.Now,
User = ViewModelLocator.Default.SettingViewModel.UserModel
};
var socket = ViewModelLocator.Default.SettingViewModel.ServerSocket;
await socket.SendMsg(msg);

msg.Horizontal = HorizontalAlignment.Right;
DispatcherHelper.CheckBeginInvokeOnUI(() => { MessageCollection.Add(msg); });
Messenger.Default.Send(msg, "NewMsgAction");
TxtMsg = null;
}


public async void MsgTextBoxKeyUp(object sender, KeyRoutedEventArgs key)
{
var textBox = sender as TextBox;
if (textBox != null) TxtMsg = textBox.Text;
if (key.Key != VirtualKey.Enter) return;
if (string.IsNullOrEmpty(TxtMsg))
return;
await SendTxtMsg();
}
}[/mw_shl_code]

本篇中不再介绍ViewModel在ViewModelLocator.cs里面的注册,ViewModel的注册上篇已经介绍过,这里的和上篇一毛一样,传送门:UWP开发之StreamSocket聊天室(三)

至此该系列文章已全部讲述完毕,贴一下最终的效果图:
***图片停止解析***


//为了方便智友查看,附上其它目录地址
***链接停止解析***
***链接停止解析***
***链接停止解析***
***链接停止解析***
***链接停止解析***


本文出自:53078485群大咖Aran

敬告:
为防止不可控的内容风险,本站已关闭新用户注册,新贴的发表及评论;
你现在看到的内容只是互联网用户曾经发表的言论快照,仅用于老用户留存纪念,且仅与科技行业相关,全部内容不代表本站观点及立场;
本站重新开放前已针对包括用户隐私、版权保护、信息安全、国家政策在内的各种互联网法律法规要求,执行了隐患内容的自查、屏蔽和删除;
本站目前所属个人主体,未有任何盈利安排与计划,且与原WFUN.COM所属公司不存在任何关联关系;
如果本帖内容或者相关资源侵犯到您的合法权益,或者您认为存在问题,那么请您务必点此举报或投诉!
全部回复:
wucd UID.573665
2015-11-17 回复

开发资料,难得难得。

本站使用Golang构建,点击此处申请开源鄂ICP备18029942号-4联系站长投诉/举报