我想要一些正确的方向,甚至是解决这个问题的方法,而且我很困难(我只是初学者/中级):
我正在尝试在我的应用程序中实现SSH。 SSH后端工作正常等,但我被困在前端。 WPF-Combination会给我一个足够的模拟控制台的解决方案吗?抛开一个完整的终端模拟,我很乐意将readline / writeline简单地写成一个看起来像控制台的东西: - )
我最好的方法是80x50单个字符网格,导致4000个单细胞,感觉就像一个完全矫枉过正。
另一个想法是制作一个控制台-Appl。绑定到另一个项目中的wpf窗口。但是......这甚至是可能的吗?
答案 0 :(得分:32)
鉴于你想模仿一个控制台,我会这样做。请注意,您必须自己处理命令并输出结果。
page.xaml
<Window x:Class="ConsoleEmulation.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" MinHeight="350" MinWidth="525" Height="350" Width="525">
<Grid>
<ScrollViewer Name="Scroller" Margin="0" Background="Black">
<StackPanel>
<ItemsControl ItemsSource="{Binding ConsoleOutput, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=.}" Foreground="White" FontFamily="Consolas"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBox Text="{Binding ConsoleInput, Mode=TwoWay}" Background="Black" Foreground="White" FontFamily="Consolas" Name="InputBlock" BorderBrush="{x:Null}" SelectionBrush="{x:Null}" />
</StackPanel>
</ScrollViewer>
</Grid>
</Window>
page.xaml.cs
public partial class MainWindow : Window
{
ConsoleContent dc = new ConsoleContent();
public MainWindow()
{
InitializeComponent();
DataContext = dc;
Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
InputBlock.KeyDown += InputBlock_KeyDown;
InputBlock.Focus();
}
void InputBlock_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
dc.ConsoleInput = InputBlock.Text;
dc.RunCommand();
InputBlock.Focus();
Scroller.ScrollToBottom();
}
}
}
public class ConsoleContent : INotifyPropertyChanged
{
string consoleInput = string.Empty;
ObservableCollection<string> consoleOutput = new ObservableCollection<string>() { "Console Emulation Sample..." };
public string ConsoleInput
{
get
{
return consoleInput;
}
set
{
consoleInput = value;
OnPropertyChanged("ConsoleInput");
}
}
public ObservableCollection<string> ConsoleOutput
{
get
{
return consoleOutput;
}
set
{
consoleOutput = value;
OnPropertyChanged("ConsoleOutput");
}
}
public void RunCommand()
{
ConsoleOutput.Add(ConsoleInput);
// do your stuff here.
ConsoleInput = String.Empty;
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propertyName)
{
if (null != PropertyChanged)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
答案 1 :(得分:3)
您是否知道可以使用AllocConsole从应用程序中显示控制台窗口?
这是一种创建“双模”应用程序的简单方法 控制台或Windows窗体应用程序。
[DllImport("kernel32")]
static extern bool AllocConsole();
或者你可以使用它:
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<TextBlock Text="Console contents..." HorizontalAlignment="Stretch" VerticalAlignment="Stretch" x:Name="ConsoleTextBlock"/>
<DockPanel Grid.Row="1">
<TextBox/>
</DockPanel>
</Grid>
为了获得更好的外观,请使用ListBox替换TextBlock,并相应地设置ItemTemplate的样式。
答案 2 :(得分:0)
我自己没有这样做,但它是我的“如果我有时间我会做的” - 项目。 因此,我仍在寻找现有的实施方式:-P
无论如何都有一些想法:
使用Visuals(即Ellipses,Textblocks)的applroach可能不是一个好主意。 想想如果你想要200x100字符会发生什么。甚至可能是后退者。把它全部留在记忆中+画它....它会非常慢。
因此,更好(甚至是正确)的方法是“吸引自己”。由于WPF是后备缓冲的,并且您不想显示任意位图,因此最可能的方法是创建一个新的UserControl并覆盖它的Paint-Method。 您可能更喜欢从Control派生,但UserControl可能有内容,因此您可以在内部显示类似连接指示器图标。
架构方面我建议创建一个包含控制台缓冲区模型的依赖属性缓冲区(ConsoleBuffer
)。另一个DP将保持左上角的位置位置(long
)。它确定了开始显示的位置(当你看后面的时候)。控制台模型我会创建一个包含char[]
和Color[]
(一维)的类。使用换行符和\n
字符来创建行(因为这是控制台的字符)。然后,如果您调整控件的大小,它将重新流动,而不需要重新分配缓冲区。
您可以使用不同大小的** ConsoleBuffer **(对于不同数量的外观字符)。
ConsoleBuffer.Write(string s)
是你做事的方法。
也许建议保持数组char[][]
数组来表示行....但这要在编程时找出。