WPF-实现仿Linux的shell功能
WPF-实现仿Linux的shell功能(终端terminal)
很多软件,如VS,IDEA都有类似Linux的shell功能,那么怎样用C#来实现该功能呢,在网上找了一下,基本没有,于是自己花了点时间大致实现了该功能,如果有时间,之后还会完善和优化一下,欢迎大家指点.
界面代码
界面很简单,基本就使用了一个TextBox。
<Window
x:Class="ch4_Terminal.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ch4_Terminal.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="20*" />
</Grid.RowDefinitions>
<TextBlock Text="终端样式:" />
<Border
x:Name="bd"
Grid.Row="1"
Background="Black"
CornerRadius="10">
<TextBox
x:Name="MyTextBox"
Margin="5"
AcceptsReturn="True"
Background="Black"
BorderBrush="White"
Foreground="White"
KeyDown="MyTextBox_KeyDown"
PreviewKeyDown="MyTextBox_PreviewKeyDown"
PreviewMouseDown="MyTextBox_PreviewMouseDown"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Hidden" />
</Border>
</Grid>
</Window>
后台逻辑代码
using ch4_Terminal.Commoms;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace ch4_Terminal.Views
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public int enterTimes = 0;
Timer timer = new Timer();
public double positionX=0;
private int i = 0;
private int j = 0;
private int m = 0;
private int n = 0;
private List<string> CmdList = new List<string>();
private string Cmd;
public MainWindow()
{
InitializeComponent();
CmdList.Clear();
}
private void MyTextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
//Point pt = e.GetPosition(this);
var a = MyTextBox.Text;
if (a == "")
{
this.MyTextBox.Text = ">";
}
else
{
if (this.MyTextBox.Text.EndsWith(">"))
{
return;
}else if (this.MyTextBox.Text.EndsWith("\n"))
{
this.MyTextBox.Text += "\n\r>";
}
}
}
private void MyTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
//Enter
if (e.KeyStates == Keyboard.GetKeyStates(Key.Enter))
{
e.Handled = true;
var a = MyTextBox.Text;
Cmd = a.Substring(a.LastIndexOf(">")+1,MyTextBox.Text.Length- a.LastIndexOf(">")-1);
if (a.EndsWith(">"+Cmd) && VerifyCmd(Cmd))
{
//MessageBox.Show("OK");
this.MyTextBox.Text += "\n" + $"{ DateTime.Now:yyyy - MM - dd HH: mm: ss}:" + $"Start \"{Cmd}\" Command is ok!\n\r>";
CmdList.Add(Cmd);
MyTextBox.SelectionStart = MyTextBox.Text.Length;
}
if (a.EndsWith(">clc"))
{
this.MyTextBox.Text = ">";
CmdList.Clear();
MyTextBox.SelectionStart = MyTextBox.Text.Length;
}
}
//Backspace
if (e.KeyStates == Keyboard.GetKeyStates(Key.Back))
{
e.Handled = true;
var a = MyTextBox.Text;
if (a.EndsWith(">"))
{
MyTextBox.SelectionStart = MyTextBox.Text.Length;
return;
} else
{
var str = a.Split('>');
var charArray = str[str.Length - 1].ToCharArray();
var NewChar = new char[charArray.Length - 1];
if (charArray.Length>0)
{
Array.Copy(charArray, NewChar, charArray.Length-1);
string s = new string(NewChar);
MyTextBox.Text = a.Remove(a.LastIndexOf(">")) + ">" + s;
MyTextBox.SelectionStart = MyTextBox.Text.Length;
}
else
{
return;
}
}
}
//Left
if (e.KeyStates == Keyboard.GetKeyStates(Key.Left))
{
i++;
e.Handled = true;
var a = MyTextBox.Text;
if (a.EndsWith(">"))
{
MyTextBox.SelectionStart = MyTextBox.Text.Length;
return;
}else
{
var str = a.Split('>');
var charArray = str[str.Length - 1].ToCharArray();
if (i<=charArray.Length)
{
MyTextBox.SelectionStart = MyTextBox.Text.Length - i;
j = charArray.Length - i;
return;
}
}
}
//Right
if (e.KeyStates == Keyboard.GetKeyStates(Key.Right))
{
j++;
e.Handled = true;
var a = MyTextBox.Text;
if (a.EndsWith(">"))
{
MyTextBox.SelectionStart = MyTextBox.Text.Length;
return;
}
else
{
var str = a.Split('>');
var charArray = str[str.Length - 1].ToCharArray();
if (j <= charArray.Length)
{
MyTextBox.SelectionStart = MyTextBox.Text.Length - charArray.Length + j;
i = charArray.Length - j;
return;
}
}
}
//Up
if (e.KeyStates == Keyboard.GetKeyStates(Key.Up))
{
m++;
e.Handled = true;
var a = MyTextBox.Text;
if (a.EndsWith(">"))
{
if (CmdList.Count > 0 && (m - 1 < CmdList.Count))
{
MyTextBox.Text += CmdList[CmdList.Count - m];
n = CmdList.Count - m;
}
MyTextBox.SelectionStart = MyTextBox.Text.Length;
}
else
{
MyTextBox.Text = a.Remove(a.LastIndexOf(">")) + ">" ;
if (CmdList.Count > 0 && (m - 1 < CmdList.Count))
{
MyTextBox.Text += CmdList[CmdList.Count - m ];
n = CmdList.Count - m;
}
MyTextBox.SelectionStart = MyTextBox.Text.Length;
}
}
//Dowm
if (e.KeyStates == Keyboard.GetKeyStates(Key.Down))
{
n++;
e.Handled = true;
var a = MyTextBox.Text;
if (a.EndsWith(">"))
{
if (CmdList.Count > 0 && (n - 1 < CmdList.Count))
{
MyTextBox.Text += CmdList[n - 1];
m = CmdList.Count - n;
}
MyTextBox.SelectionStart = MyTextBox.Text.Length;
}
else
{
MyTextBox.Text = a.Remove(a.LastIndexOf(">")) + ">";
if (CmdList.Count > 0 && (n - 1 < CmdList.Count))
{
MyTextBox.Text += CmdList[n - 1];
m = CmdList.Count - n;
}
MyTextBox.SelectionStart = MyTextBox.Text.Length;
}
}
}
private bool VerifyCmd(string cmd)
{
bool flag = false;
var str = cmd.Split(' ');
if (str.Length > 0)
{
try
{
if (str[0].ToLower().Contains("set"))//设置
{
var buf = str[1].ToLower().Split('-');
switch (buf[0])
{
case "v":
SetValue("v", Convert.ToInt32(buf[1]), Convert.ToInt32(str[2]));
break;
case "c":
SetValue("c", Convert.ToInt32(buf[1]), Convert.ToInt32(str[2]));
break;
case "t":
SetValue("t", Convert.ToInt32(buf[1]), Convert.ToInt32(str[2]));
break;
default:
break;
}
flag = true;
}
else if (str[0].ToLower().Contains("get"))//获取
{
var buf = str[1].ToLower().Split('-');
switch (buf[0])
{
case "v":
GetValue("v", Convert.ToInt32(buf[1]));
break;
case "c":
GetValue("c", Convert.ToInt32(buf[1]));
break;
case "t":
GetValue("t", Convert.ToInt32(buf[1]));
break;
default:
break;
}
flag = true;
}
else
{
flag = false;
}
}
catch (Exception ex)
{
MyTextBox.Text += "\n" + ex.ToString() + "\n\r>";
}
}
return flag;
}
private bool SetValue(string type,int Num,int Value)
{
MessageBox.Show($"走通讯协议 Set {type}-{Num} {Value}");
//MyTextBox.Text += "\n" + $"{ DateTime.Now:yyyy - MM - dd HH: mm: ss}:" + $"Start \"{Cmd}\" Command is ok!\n\r>";
return true;
}
private bool GetValue(string type, int Num)
{
MessageBox.Show($"走通讯协议 Set {type}-{Num}");
//MyTextBox.Text += "\n" + $"{ DateTime.Now:yyyy - MM - dd HH: mm: ss}:" + $"Start \"{Cmd}\" Command is ok!\n\r>";
return true;
}
}
}
进入终端界面:
终端命令都是以“>"来开头
成功运行后的界面:
完善:
TextBox控件属性增加:
InputMethod.IsInputMethodEnabled="False"
PreviewTextInput="TextBox_PreviewTextInput"
InputMethod.IsInputMethodEnabled=“False” 是禁止输入法;PreviewTextInput="TextBox_PreviewTextInput"是对输入进行限制,使用正则表达式限制
private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
Regex re = new Regex(@"[^\u4e00-\u9fa5]");//限制中文字符
e.Handled = !re.IsMatch(e.Text);
}
后台需要实现的功能可以在VerifyCmd函数中添加。