15

正しい方向へのヒント、またはこの問題の解決策が欲しいのですが、かなり行き詰まっています(私は初心者/中級者です):

アプリケーションに SSH を実装しようとしています。SSH バックエンドは正常に動作しますが、フロントエンドで立ち往生しています。コンソールをエミュレートするための適切なソリューションを提示してくれる WPF の組み合わせは何ですか? 完全な端末エミュレーションは別として、単純にコンソールのようなものに readline/writeline を実行できれば幸いです :-)

私のこれまでの最善のアプローチは、単一文字の 80x50 グリッドであり、結果として 4000 個の単一セルになりましたが、これは完全にやり過ぎのように感じます。

別のアイデアは、コンソール アプリケーションを作成することでした。別のプロジェクトの wpf-window にバインドされています。しかし...それは可能ですか?

4

3 に答える 3

37

コンソールをエミュレートしたい場合は、このようにします。コマンドを処理し、結果を自分で出力する必要があることに注意してください。

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));
    }
}
于 2013-02-19T12:27:05.400 に答える
4

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>

見栄えを良くするには、TextBlock を ListBox に置き換え、それに応じて ItemTemplate のスタイルを設定します。

于 2013-02-19T11:35:59.733 に答える
1

自分ではやっていませんが、「時間があればやってみたい」企画の一つです。したがって、私はまだ既存の実装を探しています:-P

とにかくいくつかの考え:

ビジュアル (つまり、楕円、テキストブロック) を使用するアプローチは、おそらく良いアイデアではありません。200x100 文字が必要な場合に何が起こるかを考えてみてください。多分バックバッファですら。すべてをメモリに保持して描画する....信じられないほど遅くなります。

したがって、より良い(または正しい)アプローチは、「自分で描く」ことです。WPF はバックバッファリングされており、任意のビットマップを表示したくないため、最も可能性の高い方法は、新しい UserControl を作成し、その Paint-Method をオーバーライドすることです。Control から派生することを好むかもしれませんが、UserControl には Content が含まれている可能性があるため、内部に接続インジケーター アイコンのようなものを表示できます。

アーキテクチャに関しては、コンソール バッファ モデルを保持する依存プロパティBuffer ( ) を作成することをお勧めします。ConsoleBuffer別の DP は、左上の位置( long) を保持します。表示を開始する場所を決定します (後ろを見ている間)。char[]コンソール モデルでは、aと a Color[](1 次元)を含むクラスを作成します。改行と\n文字を使用して行を作成します (これはコンソールの文字であるため)。次に、コントロールのサイズを変更すると、バッファを再割り当てする必要なくリフローします。さまざまなサイズの **ConsoleBuffer** を操作できます (さまざまな数の後方文字用)。

ConsoleBuffer.Write(string s)物事を行うためのあなたの方法です。

行を表すために配列の配列を保持することをお勧めしますchar[][]....しかし、それはプログラミング中に見つけるまでです。

于 2014-08-20T16:49:03.020 に答える