This commit is contained in:
lxmou666 2021-02-22 14:44:47 +08:00
parent ba5f72c73e
commit 2d3c116a32
17 changed files with 428 additions and 36 deletions

View File

@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JianGongYun", "JianGongYun\
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClientDemo", "ClientDemo\ClientDemo.csproj", "{5C83270B-1086-494D-BCAF-0E773CC598AB}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClientDemo", "ClientDemo\ClientDemo.csproj", "{5C83270B-1086-494D-BCAF-0E773CC598AB}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WSDemo", "WSDemo\WSDemo.csproj", "{A748F095-84EF-4D1B-A1B1-842ADCD73D6C}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -41,6 +43,18 @@ Global
{5C83270B-1086-494D-BCAF-0E773CC598AB}.Release|x64.Build.0 = Release|Any CPU {5C83270B-1086-494D-BCAF-0E773CC598AB}.Release|x64.Build.0 = Release|Any CPU
{5C83270B-1086-494D-BCAF-0E773CC598AB}.Release|x86.ActiveCfg = Release|Any CPU {5C83270B-1086-494D-BCAF-0E773CC598AB}.Release|x86.ActiveCfg = Release|Any CPU
{5C83270B-1086-494D-BCAF-0E773CC598AB}.Release|x86.Build.0 = Release|Any CPU {5C83270B-1086-494D-BCAF-0E773CC598AB}.Release|x86.Build.0 = Release|Any CPU
{A748F095-84EF-4D1B-A1B1-842ADCD73D6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A748F095-84EF-4D1B-A1B1-842ADCD73D6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A748F095-84EF-4D1B-A1B1-842ADCD73D6C}.Debug|x64.ActiveCfg = Debug|Any CPU
{A748F095-84EF-4D1B-A1B1-842ADCD73D6C}.Debug|x64.Build.0 = Debug|Any CPU
{A748F095-84EF-4D1B-A1B1-842ADCD73D6C}.Debug|x86.ActiveCfg = Debug|Any CPU
{A748F095-84EF-4D1B-A1B1-842ADCD73D6C}.Debug|x86.Build.0 = Debug|Any CPU
{A748F095-84EF-4D1B-A1B1-842ADCD73D6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A748F095-84EF-4D1B-A1B1-842ADCD73D6C}.Release|Any CPU.Build.0 = Release|Any CPU
{A748F095-84EF-4D1B-A1B1-842ADCD73D6C}.Release|x64.ActiveCfg = Release|Any CPU
{A748F095-84EF-4D1B-A1B1-842ADCD73D6C}.Release|x64.Build.0 = Release|Any CPU
{A748F095-84EF-4D1B-A1B1-842ADCD73D6C}.Release|x86.ActiveCfg = Release|Any CPU
{A748F095-84EF-4D1B-A1B1-842ADCD73D6C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -6,5 +6,6 @@
<add key="LIVEAppID" value="1302772646"/> <add key="LIVEAppID" value="1302772646"/>
<add key="LIVEBizid" value="110962"/> <add key="LIVEBizid" value="110962"/>
<add key="RoomId" value ="654657754"/> <add key="RoomId" value ="654657754"/>
<add key="WSUrl" value ="wss://web.cqjgjyw.cn/websocket"/>
</appSettings> </appSettings>
</configuration> </configuration>

View File

@ -18,6 +18,7 @@
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.5.1.20201229" /> <PackageReference Include="OpenCvSharp4.runtime.win" Version="4.5.1.20201229" />
<PackageReference Include="OpenCvSharp4.WpfExtensions" Version="4.5.1.20201229" /> <PackageReference Include="OpenCvSharp4.WpfExtensions" Version="4.5.1.20201229" />
<PackageReference Include="Websocket.Client" Version="4.3.30" />
<PackageReference Include="zlib.net-mutliplatform" Version="1.0.4" /> <PackageReference Include="zlib.net-mutliplatform" Version="1.0.4" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'net45'"> <ItemGroup Condition="'$(TargetFramework)' != 'net45'">

View File

@ -2,7 +2,7 @@
"profiles": { "profiles": {
"JianGongYun": { "JianGongYun": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "sznykt://--classhead|测试课程1|--classsubhead|测试章节1|--teacherid|12345678|--teachername|王大锤", "commandLineArgs": "sznykt://--classhead|测试课程1|--classsubhead|测试章节1|--teacherid|1234_5678|--teachername|王大锤|endtime|MjAyMS0wMy0xOCAyMTo1MDowMA==",
"nativeDebugging": false "nativeDebugging": false
} }
} }

View File

@ -71,7 +71,7 @@
<Setter Property="Stylus.IsFlicksEnabled" Value="false"/> <Setter Property="Stylus.IsFlicksEnabled" Value="false"/>
<Setter Property="Background" Value="Transparent"/> <Setter Property="Background" Value="Transparent"/>
<Setter Property="Margin" Value="0,1,1,6"/> <Setter Property="Margin" Value="0,1,1,6"/>
<Setter Property="Width" Value="10"/> <Setter Property="Width" Value="5"/>
<Setter Property="MinWidth" Value="5"/> <Setter Property="MinWidth" Value="5"/>
<Setter Property="Opacity" Value="0.2"/> <Setter Property="Opacity" Value="0.2"/>
<Setter Property="Template"> <Setter Property="Template">

View File

@ -21,6 +21,9 @@ using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using AduSkin.Controls.Metro; using AduSkin.Controls.Metro;
using System.Configuration; using System.Configuration;
using Websocket.Client;
using System.Windows.Threading;
using Newtonsoft.Json.Linq;
namespace JianGongYun.TRTC namespace JianGongYun.TRTC
{ {
@ -37,6 +40,7 @@ namespace JianGongYun.TRTC
static string SDKAppKEY { get { return ConfigurationManager.AppSettings[nameof(SDKAppKEY)]; } } static string SDKAppKEY { get { return ConfigurationManager.AppSettings[nameof(SDKAppKEY)]; } }
static uint LIVEAppID { get { return uint.Parse(ConfigurationManager.AppSettings[nameof(LIVEAppID)]); } } static uint LIVEAppID { get { return uint.Parse(ConfigurationManager.AppSettings[nameof(LIVEAppID)]); } }
static uint LIVEBizid { get { return uint.Parse(ConfigurationManager.AppSettings[nameof(LIVEBizid)]); } } static uint LIVEBizid { get { return uint.Parse(ConfigurationManager.AppSettings[nameof(LIVEBizid)]); } }
static string WSUrl { get { return ConfigurationManager.AppSettings[nameof(WSUrl)]; } }
/// <summary> /// <summary>
/// TRTC实例 /// TRTC实例
@ -53,10 +57,18 @@ namespace JianGongYun.TRTC
/// <summary> /// <summary>
/// 直播窗口 /// 直播窗口
/// </summary> /// </summary>
public static Window CurrentLiveWindow; public static LiveWindow CurrentLiveWindow;
private static LiveWindowViewModel liveWinMode; private static LiveWindowViewModel liveWinMode;
public static ClassroomEntity CurrentClassroomEntity { get; private set; } public static ClassroomEntity CurrentClassroomEntity { get; private set; }
public static TRTCCloudCallback TRTCCloudCallback = new TRTCCloudCallback(); public static TRTCCloudCallback TRTCCloudCallback = new TRTCCloudCallback();
/// <summary>
/// ws客户端
/// </summary>
public static WebsocketClient WSClient = null;
public static DispatcherTimer Heartbeat = null;
public static string ClassId = null;//章节id
/// <summary> /// <summary>
/// 摄像头帧 /// 摄像头帧
/// </summary> /// </summary>
@ -121,6 +133,30 @@ namespace JianGongYun.TRTC
_RecoderDir = $"{classroomEntity.ClassHead}_{classroomEntity.ClassSubHead}"; _RecoderDir = $"{classroomEntity.ClassHead}_{classroomEntity.ClassSubHead}";
//连接WS
if (WSClient != null && WSClient.IsRunning)//只连一个
{
WSClient.Stop(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, "connect repeat");
WSClient.Dispose();
}
var url = new Uri(WSUrl);
WSClient = new WebsocketClient(url);
WSClient.ReconnectTimeout = TimeSpan.FromSeconds(30);
WSClient.ReconnectionHappened.Subscribe(info =>
Console.WriteLine($"Reconnection happened, type: {info.Type}"));
WSClient.MessageReceived.Subscribe(CurrentLiveWindow.OnMsg);
WSClient.Start();
ClassId = CurrentClassroomEntity.TeacherId.Split('_')[1];
WSClient.Send($"{{code:10000,nick:\"{CurrentClassroomEntity.TeacherName}\",\"room\":\"push_{ClassId}\"}}");//进房间
//发送心跳包
Heartbeat = new DispatcherTimer(DispatcherPriority.Render);
Heartbeat.Interval = TimeSpan.FromSeconds(5);
Heartbeat.Tick += new EventHandler((a, b) => WSClient.Send("{code:10016}"));
Heartbeat.Start();
callerWindow?.Hide();//隐藏调用窗口 callerWindow?.Hide();//隐藏调用窗口
CurrentLiveWindow.Show(); CurrentLiveWindow.Show();
} }
@ -744,6 +780,11 @@ namespace JianGongYun.TRTC
CurrentLiveWindow = null; CurrentLiveWindow = null;
CurrentClassroomEntity = null; CurrentClassroomEntity = null;
Heartbeat.Stop();
WSClient.Stop(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, "end");
WSClient.Dispose();
WSClient = null;
Heartbeat = null;
lTXDeviceManager.Dispose(); lTXDeviceManager.Dispose();
lTXDeviceManager = null; lTXDeviceManager = null;

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace JianGongYun.TRTC.Models
{
public class ChatEntity
{
public string Body { get; set; }
public string Nick { get; set; }
public string Date { get; set; }
}
}

View File

@ -25,6 +25,10 @@ namespace JianGongYun.TRTC.Models
/// 章节名称 /// 章节名称
/// </summary> /// </summary>
public string ClassSubHead { get; set; } public string ClassSubHead { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public DateTime? EndTime { get; set; }
} }
} }

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows.Data;
using System.Windows.Media;
namespace JianGongYun.TRTC
{
public class ChatItemBgConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)) : parameter;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}

View File

@ -28,7 +28,7 @@ namespace JianGongYun.TRTC.ViewModels
/// <summary> /// <summary>
/// 学生总数 /// 学生总数
/// </summary> /// </summary>
private int _StudentCount = 1; private int _StudentCount = 0;
public int StudentCount public int StudentCount
{ {
set set
@ -356,15 +356,15 @@ namespace JianGongYun.TRTC.ViewModels
/// <summary> /// <summary>
/// 消息集合 /// 消息集合
/// </summary> /// </summary>
private ObservableCollection<string> _Chats = new ObservableCollection<string>() { "1", "2" }; private ObservableCollection<ChatEntity> _Chats = new ObservableCollection<ChatEntity>();
public ObservableCollection<string> Chats public ObservableCollection<ChatEntity> Chats
{ {
set set
{ {
_Chats = value; _Chats = value;
if (PropertyChanged != null) if (PropertyChanged != null)
{ {
PropertyChanged(this, new PropertyChangedEventArgs("Chats"));//对StudentCount进行监听 PropertyChanged(this, new PropertyChangedEventArgs("Chats"));
} }
} }
get get

View File

@ -62,7 +62,7 @@
<TextBlock FontSize="14" Padding="3 0 0 0" Foreground="#bbbbbb" Text="人"></TextBlock> <TextBlock FontSize="14" Padding="3 0 0 0" Foreground="#bbbbbb" Text="人"></TextBlock>
</StackPanel> </StackPanel>
<Metro:AduFlatButton Content="开始直播" Click="StartLive_Click" Tag="True" Canvas.Bottom="13" Canvas.Right="25" Visibility="{Binding IsLive, Converter={StaticResource UnVisibilityOfBool}}"></Metro:AduFlatButton> <Metro:AduFlatButton Content="开始直播" Click="StartLive_Click" Tag="True" Canvas.Bottom="13" Canvas.Right="25" Visibility="{Binding IsLive, Converter={StaticResource UnVisibilityOfBool}}"></Metro:AduFlatButton>
<Metro:AduFlatButton Content="结束直播" Click="StartLive_Click" Tag="False" Type="error" Canvas.Bottom="13" Canvas.Right="25" Visibility="{Binding IsLive, Converter={StaticResource VisibilityOfBool}}"></Metro:AduFlatButton> <Metro:AduFlatButton Content="结束直播" x:Name="stoplive" Click="StartLive_Click" Tag="False" Type="error" Canvas.Bottom="13" Canvas.Right="25" Visibility="{Binding IsLive, Converter={StaticResource VisibilityOfBool}}"></Metro:AduFlatButton>
<StackPanel Visibility="{Binding IsLive, Converter={StaticResource VisibilityOfBool}}" Orientation="Horizontal" Canvas.Bottom="20" Canvas.Right="150"> <StackPanel Visibility="{Binding IsLive, Converter={StaticResource VisibilityOfBool}}" Orientation="Horizontal" Canvas.Bottom="20" Canvas.Right="150">
<Ellipse VerticalAlignment="Center" Width="10" Fill="#00cc66" Height="10"></Ellipse> <Ellipse VerticalAlignment="Center" Width="10" Fill="#00cc66" Height="10"></Ellipse>
<TextBlock FontSize="15" Foreground="White" Margin="7 0 0 0">直播中</TextBlock> <TextBlock FontSize="15" Foreground="White" Margin="7 0 0 0">直播中</TextBlock>
@ -70,7 +70,63 @@
</StackPanel> </StackPanel>
</Canvas> </Canvas>
<!--右方聊天学员面板--> <!--右方聊天学员面板-->
<Canvas DockPanel.Dock="Right" Width="280" Background="#2f3035"> <Canvas x:Name="ChatWrap" DockPanel.Dock="Right" Width="280" Background="#2f3035">
<DockPanel Height="{Binding ElementName=ChatWrap,Path=ActualHeight}" Width="{Binding ElementName=ChatWrap,Path=ActualWidth}">
<DockPanel Height="60" DockPanel.Dock="Bottom">
<Button PreviewKeyDown="Button_PreviewKeyDown" Click="Button_Click" Foreground="White" Background="#3e7fff" Margin="0 12 12 12" Width="70" DockPanel.Dock="Right">发 送</Button>
<TextBox x:Name="ChatIpt" PreviewKeyDown="TextBox_PreviewKeyDown" VerticalContentAlignment="Center" Padding="12 0" Foreground="White" Background="Transparent" Margin="12 12 0 12"></TextBox>
</DockPanel>
<Border BorderBrush="#888" BorderThickness="0 0 0 1">
<Grid>
<local:ScrollingListBox x:Name="ChatList" BorderThickness="0" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding Chats}" Background="Transparent">
<ListBox.Resources>
<Style TargetType="ScrollViewer" BasedOn="{StaticResource CusScroll}"></Style>
<Style TargetType="local:ScrollingListBox">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="Border" BorderThickness="0">
<Label x:Name="Label" VerticalAlignment="Center" Padding="12" HorizontalAlignment="Left" FontSize="13px">
<ContentPresenter></ContentPresenter>
</Label>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="BorderBrush" Value="#efefef"></Setter>
<!--<Setter TargetName="Border" Property="Background" Value="{StaticResource itembg}"></Setter>-->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<!--自定义ListBox项样式-->
<DataTemplate>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="#3c77eb" TextWrapping="Wrap" Text="{Binding Path=Nick}">
</TextBlock>
<TextBlock Margin="6 0 0 0" Foreground="#888888" TextWrapping="Wrap" Text="{Binding Path=Date}">
</TextBlock>
</StackPanel>
<TextBlock Margin="0 6 0 0" Foreground="White" TextWrapping="Wrap" Text="{Binding Path=Body}">
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</local:ScrollingListBox>
</Grid>
</Border>
</DockPanel>
</Canvas> </Canvas>
<!--下方教程面板--> <!--下方教程面板-->
<Canvas DockPanel.Dock="Bottom" Height="30" Background="#2a2b30"> <Canvas DockPanel.Dock="Bottom" Height="30" Background="#2a2b30">
@ -205,6 +261,7 @@
<TextBlock Foreground="White" FontSize="20" FontWeight="Bold" Padding="10" HorizontalAlignment="Center" VerticalAlignment="Center">请选择要分享的屏幕或前台窗口(上课期间可随时切换)</TextBlock> <TextBlock Foreground="White" FontSize="20" FontWeight="Bold" Padding="10" HorizontalAlignment="Center" VerticalAlignment="Center">请选择要分享的屏幕或前台窗口(上课期间可随时切换)</TextBlock>
</StackPanel> </StackPanel>
<!--列表视图--> <!--列表视图-->
<!--Style="{StaticResource CusScroll}"-->
<ScrollViewer Style="{StaticResource CusScroll}" Canvas.Right="0" Canvas.Top="50" Height="480" Width="{Binding ElementName=ScrollWrap,Path=ActualWidth}"> <ScrollViewer Style="{StaticResource CusScroll}" Canvas.Right="0" Canvas.Top="50" Height="480" Width="{Binding ElementName=ScrollWrap,Path=ActualWidth}">
<ListBox MouseUp="ShareList_Selected" SelectedValuePath="Info" SelectedValue="{Binding CurrentShareScreen}" ItemsSource="{Binding LiveScreens}" Template="{StaticResource ShareListTemplate}" ItemTemplate="{StaticResource ShareListItemTemplate}"></ListBox> <ListBox MouseUp="ShareList_Selected" SelectedValuePath="Info" SelectedValue="{Binding CurrentShareScreen}" ItemsSource="{Binding LiveScreens}" Template="{StaticResource ShareListTemplate}" ItemTemplate="{StaticResource ShareListItemTemplate}"></ListBox>
</ScrollViewer> </ScrollViewer>

View File

@ -16,6 +16,9 @@ using System.Windows.Threading;
using JianGongYun.TRTC.Components; using JianGongYun.TRTC.Components;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.ComponentModel; using System.ComponentModel;
using Websocket.Client;
using Newtonsoft.Json.Linq;
using System.Diagnostics;
namespace JianGongYun.TRTC.Windows namespace JianGongYun.TRTC.Windows
{ {
@ -34,15 +37,80 @@ namespace JianGongYun.TRTC.Windows
InitializeComponent(); InitializeComponent();
this.Icon = new BitmapImage(new Uri("logo.ico", UriKind.RelativeOrAbsolute)); this.Icon = new BitmapImage(new Uri("logo.ico", UriKind.RelativeOrAbsolute));
NoticeManager.Initialize(); NoticeManager.Initialize();
//AttachConsole(-1);//把进程挂在控制台,通过命令行启动程序可以看到控制台输出 AttachConsole(-1);//把进程挂在控制台,通过命令行启动程序可以看到控制台输出
LiveWindowViewModel = new ViewModels.LiveWindowViewModel(); LiveWindowViewModel = new ViewModels.LiveWindowViewModel();
SettingWindowViewModel = ViewModels.SettingWindowViewModel.GetInstance(); SettingWindowViewModel = ViewModels.SettingWindowViewModel.GetInstance();
this.DataContext = LiveWindowViewModel; this.DataContext = LiveWindowViewModel;
BorderBrush = new SolidColorBrush(color: Color.FromRgb(42, 43, 48));//窗口标题背景颜色 BorderBrush = new SolidColorBrush(color: Color.FromRgb(42, 43, 48));//窗口标题背景颜色
for (int i = 0; i < 12; i++)
{
LiveWindowViewModel.Chats.Add(new Models.ChatEntity());//放几个空聊天数据占位置
}
Loaded += LiveWindowRightBottomBlock_Loaded1;
}
private void LiveWindowRightBottomBlock_Loaded1(object sender, RoutedEventArgs e)
{
if (ChatList.Items.Count > 0)
{
ChatList.ScrollIntoView(ChatList.Items[ChatList.Items.Count - 1]);
}
} }
/// <summary>
/// ws消息
/// </summary>
/// <param name="msg"></param>
public void OnMsg(ResponseMessage msg)
{
Debug.Print(msg.Text);
Console.WriteLine($"Message received: {msg}");
if (msg.MessageType == System.Net.WebSockets.WebSocketMessageType.Text)
{
var data = JObject.Parse(msg.Text);
var temp = data.SelectToken("extend.code");
if (temp != null)
{
var code = temp.ToObject<int>();
switch (code)
{
case 20001:
var count = data.SelectToken("extend.mess").ToObject<int>();
LiveWindowViewModel.StudentCount = count;
break;
case 30004://心跳包返回的时间
if (DateTime.TryParse(data.SelectToken("extend.date").ToObject<string>(), out var date))
{
if (date > LiveClassroom.CurrentClassroomEntity.EndTime)//结束时间关闭直播
{
this.Dispatcher.Invoke(new Action(() =>
{
AduMessageBox.ShowOK("已到结束时间", "提醒", "确定");
StartLive_Click(stoplive, null);
}));
}
}
break;
}
return;
}
temp = data.SelectToken("body");
if (temp != null)//发送消息后服务器的返回
{
var body = data["body"].ToString();
var nick = data["extend"]["nick"].ToString();
var time = data["extend"]["time"].ToString();
this.Dispatcher.Invoke(new Action(() =>
{
if (LiveWindowViewModel.Chats.Count > 520)
{
LiveWindowViewModel.Chats.RemoveAt(0);
}
LiveWindowViewModel.Chats.Add(new Models.ChatEntity { Body = body, Nick = nick, Date = time });
}));
}
}
}
protected override void OnActivated(EventArgs e) protected override void OnActivated(EventArgs e)
{ {
@ -362,5 +430,40 @@ namespace JianGongYun.TRTC.Windows
this.Hide(); this.Hide();
blockTop.Show(); blockTop.Show();
} }
public void SendMsg(TextBox text)
{
if (!string.IsNullOrEmpty(text.Text))
{
//LiveWindow.LiveWindowViewModel.Chats.Add(new Models.ChatEntity { Body = text.Text });//往Chats集合添加数据会自动更新到界面上
LiveClassroom.WSClient.Send($"{{\"code\":10086,\"mess\":\"{text.Text}\",\"room\":\"push_{LiveClassroom.ClassId}\"}}");
text.Text = "";
}
}
private void Button_PreviewKeyDown(object sender, KeyEventArgs e)
{
//输入框回车
if (e.Key == Key.Enter)
{
SendMsg(ChatIpt);
}
}
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
//输入框回车
if (e.Key == Key.Enter)
{
var text = (TextBox)sender;
SendMsg(text);
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
SendMsg(ChatIpt);
}
} }
} }

View File

@ -4,6 +4,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:JianGongYun.TRTC.Windows" xmlns:local="clr-namespace:JianGongYun.TRTC.Windows"
xmlns:System="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d" mc:Ignorable="d"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False" ShowInTaskbar="False"
@ -12,22 +13,26 @@
AllowsTransparency="True" AllowsTransparency="True"
Background="Transparent" Background="Transparent"
MouseDown="Window_MouseDown" MouseDown="Window_MouseDown"
xmlns:live="clr-namespace:JianGongYun.TRTC"
Title="" Height="600" Width="200"> Title="" Height="600" Width="200">
<Window.Resources> <Window.Resources>
<System:Double x:Key="rd">9</System:Double>
<SolidColorBrush x:Key="itembg" Color="#50000000" />
<System:Double x:Key="ipth">35</System:Double>
<System:Double x:Key="far">5</System:Double>
<CornerRadius x:Key="fullrd" TopLeft="{StaticResource rd}" TopRight="{StaticResource rd}" BottomRight="{StaticResource rd}" BottomLeft="{StaticResource rd}"></CornerRadius>
<CornerRadius x:Key="arird" TopLeft="{StaticResource rd}" TopRight="{StaticResource rd}" BottomRight="{StaticResource rd}" BottomLeft="0"></CornerRadius>
<Thickness x:Key="fullfar" Left="{StaticResource far}" Top="{StaticResource far}" Bottom="{StaticResource far}" Right="{StaticResource far}"></Thickness>
<Thickness x:Key="hfar" Left="{StaticResource far}" Right="{StaticResource far}"></Thickness>
<Style x:Key="placeHolder" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}"> <Style x:Key="placeHolder" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}"> <ControlTemplate TargetType="{x:Type TextBox}">
<Grid> <Grid>
<TextBox Padding="14,0,14,0" VerticalContentAlignment="Center" Text="{Binding Path=Text, <TextBox Margin="0" Padding="{StaticResource hfar}" BorderThickness="0" VerticalContentAlignment="Center" Text="{Binding Path=Text,RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" x:Name="textSource" Background="Transparent" Foreground="White" Panel.ZIndex="2" />
RelativeSource={RelativeSource TemplatedParent}, <TextBox Margin="0" Padding="{StaticResource hfar}" BorderThickness="0" VerticalContentAlignment="Center" Text="{TemplateBinding Tag}" Background="{TemplateBinding Background}" Panel.ZIndex="1">
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
x:Name="textSource"
Background="Transparent"
Foreground="White"
Panel.ZIndex="2" />
<TextBox Padding="14,0,14,0" VerticalContentAlignment="Center" Text="{TemplateBinding Tag}" Background="{TemplateBinding Background}" Panel.ZIndex="1">
<TextBox.Style> <TextBox.Style>
<Style TargetType="{x:Type TextBox}"> <Style TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="Transparent"/> <Setter Property="Foreground" Value="Transparent"/>
@ -38,17 +43,22 @@
</Style.Triggers> </Style.Triggers>
</Style> </Style>
</TextBox.Style> </TextBox.Style>
<TextBox.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="{StaticResource fullrd}"/>
<Setter Property="BorderBrush" Value="#c1d0dc"/>
</Style>
</TextBox.Resources>
</TextBox> </TextBox>
</Grid> </Grid>
</ControlTemplate> </ControlTemplate>
</Setter.Value> </Setter.Value>
</Setter> </Setter>
</Style> </Style>
<BooleanToVisibilityConverter x:Key="VisibilityOfBool" /> <BooleanToVisibilityConverter x:Key="VisibilityOfBool" />
<!--自定义ListBox项样式--> <live:ChatItemBgConverter x:Key="BgByVal" />
<DataTemplate x:Key="cusItem">
<TextBlock Foreground="White" Text="{Binding}"></TextBlock>
</DataTemplate>
</Window.Resources> </Window.Resources>
<DockPanel> <DockPanel>
<!--预览框--> <!--预览框-->
@ -62,14 +72,53 @@
</Canvas> </Canvas>
</Grid> </Grid>
<!--聊天版面--> <!--聊天版面-->
<Grid Background="#33000000"> <Grid Background="#01000000">
<DockPanel> <DockPanel>
<!--输入框--> <!--输入框-->
<DockPanel DockPanel.Dock="Bottom" Height="30"> <DockPanel Margin="{StaticResource fullfar}" DockPanel.Dock="Bottom" Height="{StaticResource ipth}">
<TextBox Background="Transparent" Foreground="White" Style="{StaticResource placeHolder}" PreviewKeyDown="TextBox_PreviewKeyDown" Tag="输入"></TextBox> <TextBox Background="{StaticResource itembg}" Height="{StaticResource ipth}" Padding="{StaticResource fullfar}" Foreground="White" Style="{StaticResource placeHolder}" PreviewKeyDown="TextBox_PreviewKeyDown" Tag="输入"></TextBox>
</DockPanel> </DockPanel>
<!--消息列表--> <!--消息列表-->
<ListBox ItemTemplate="{StaticResource cusItem}" ItemsSource="{Binding Chats}" Background="Transparent"></ListBox> <local:ScrollingListBox x:Name="ChatList" BorderThickness="0" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding Chats}" Background="Transparent">
<ListBox.Resources>
<Style TargetType="ScrollViewer" BasedOn="{StaticResource CusScroll}"></Style>
<Style TargetType="local:ScrollingListBox">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="Border" Padding="{StaticResource fullfar}" Margin="{StaticResource fullfar}" BorderThickness="0" Background="{Binding Path=Body,Converter={StaticResource BgByVal},ConverterParameter={StaticResource itembg}}" CornerRadius="{StaticResource arird}">
<Label x:Name="Label" VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="12px">
<ContentPresenter></ContentPresenter>
</Label>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="BorderBrush" Value="#efefef"></Setter>
<Setter TargetName="Border" Property="Background" Value="{StaticResource itembg}"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<!--自定义ListBox项样式-->
<DataTemplate>
<StackPanel>
<TextBlock Foreground="White" TextWrapping="Wrap" Text="{Binding Path=Body}">
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</local:ScrollingListBox>
</DockPanel> </DockPanel>
</Grid> </Grid>
</DockPanel> </DockPanel>

View File

@ -15,6 +15,21 @@ using System.Windows.Shapes;
namespace JianGongYun.TRTC.Windows namespace JianGongYun.TRTC.Windows
{ {
public class ScrollingListBox : ListBox
{
protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems == null) return;
var newItemCount = e.NewItems.Count;
if (newItemCount > 0)
this.ScrollIntoView(e.NewItems[newItemCount - 1]);
base.OnItemsChanged(e);
}
}
/// <summary> /// <summary>
/// LiveWindowRightBottomBlock.xaml 的交互逻辑 /// LiveWindowRightBottomBlock.xaml 的交互逻辑
/// </summary> /// </summary>
@ -40,6 +55,16 @@ namespace JianGongYun.TRTC.Windows
this.Top += 100; this.Top += 100;
Loaded += LiveWindowRightBottomBlock_Loaded; Loaded += LiveWindowRightBottomBlock_Loaded;
} }
Loaded += LiveWindowRightBottomBlock_Loaded1;
}
private void LiveWindowRightBottomBlock_Loaded1(object sender, RoutedEventArgs e)
{
if (ChatList.Items.Count > 0)
{
ChatList.ScrollIntoView(ChatList.Items[ChatList.Items.Count - 1]);
}
} }
private void LiveWindowRightBottomBlock_Loaded(object sender, RoutedEventArgs e) private void LiveWindowRightBottomBlock_Loaded(object sender, RoutedEventArgs e)
@ -56,6 +81,7 @@ namespace JianGongYun.TRTC.Windows
PreVideoWrap.Children.Add(view); PreVideoWrap.Children.Add(view);
view.SetPause(false); view.SetPause(false);
} }
} }
protected override void OnClosing(CancelEventArgs e) protected override void OnClosing(CancelEventArgs e)
@ -90,10 +116,9 @@ namespace JianGongYun.TRTC.Windows
if (e.Key == Key.Enter) if (e.Key == Key.Enter)
{ {
var text = (TextBox)sender; var text = (TextBox)sender;
//socket.send(text.Text); LiveWindow.SendMsg(text);
LiveWindow.LiveWindowViewModel.Chats.Add(text.Text);//往Chats集合添加数据会自动更新到界面上
text.Text = "";
} }
} }
} }
} }

View File

@ -27,11 +27,12 @@ namespace JianGongYun.Views
const string CLASS_SUB_HEAD = "--classsubhead"; const string CLASS_SUB_HEAD = "--classsubhead";
const string TEACHER_ID = "--teacherid"; const string TEACHER_ID = "--teacherid";
const string TEACHER_NAME = "--teachername"; const string TEACHER_NAME = "--teachername";
const string END_TIME = "endtime";
public Login() public Login()
{ {
InitializeComponent(); InitializeComponent();
this.Icon = new BitmapImage(new Uri("logo.ico", UriKind.Relative)); this.Icon = new BitmapImage(new Uri("logo.ico", UriKind.Relative));
string errMsg = "", classHead = default, classSubHead = default, teacherId = default, teacherName = default; string errMsg = "", classHead = default, classSubHead = default, teacherId = default, teacherName = default, endtime = default;
var urltemps = Environment.GetCommandLineArgs(); var urltemps = Environment.GetCommandLineArgs();
if (urltemps.Length < 2) if (urltemps.Length < 2)
{ {
@ -77,6 +78,14 @@ namespace JianGongYun.Views
} }
teacherName = args[indexTemp + 1]; teacherName = args[indexTemp + 1];
indexTemp = Array.IndexOf(args, END_TIME);
if (indexTemp < 0)
{
errMsg = $"{nameof(END_TIME)} NULL";
goto Skip;
}
endtime = args[indexTemp + 1];
Skip: Skip:
if (!string.IsNullOrWhiteSpace(errMsg)) if (!string.IsNullOrWhiteSpace(errMsg))
{ {
@ -90,7 +99,8 @@ namespace JianGongYun.Views
ClassHead = classHead, ClassHead = classHead,
ClassSubHead = classSubHead, ClassSubHead = classSubHead,
TeacherId = teacherId, TeacherId = teacherId,
TeacherName = teacherName TeacherName = teacherName,
EndTime = string.IsNullOrEmpty(endtime) ? null : new DateTime?(DateTime.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(endtime))))
}); });
} }
} }

39
WSDemo/Program.cs Normal file
View File

@ -0,0 +1,39 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Websocket.Client;
namespace WSDemo
{
class Program
{
static void Main(string[] args)
{
var exitEvent = new ManualResetEvent(false);
var url = new Uri("wss://web.cqjgjyw.cn/websocket");
using (var client = new WebsocketClient(url))
{
client.ReconnectTimeout = TimeSpan.FromSeconds(30);
client.ReconnectionHappened.Subscribe(info =>
Console.WriteLine($"Reconnection happened, type: {info.Type}"));
client.MessageReceived.Subscribe(msg => Console.WriteLine($"Message received: {msg}"));
client.StartOrFail();
Task.Run(() => client.Send("{code:10000,nick:\"张三\",\"room\":\"push_5678\"}"));
Task.Run(() =>
{
while (true)
{
client.Send($"{{\"code\":10086,\"mess\":\"{Guid.NewGuid()}\",\"room\":\"push_5678\"}}");
client.Send("{code:10016}");
Thread.Sleep(5000);
}
});
exitEvent.WaitOne();
}
}
}
}

13
WSDemo/WSDemo.csproj Normal file
View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Websocket.Client" Version="4.3.30" />
</ItemGroup>
</Project>