我有一个控制台应用程序,它运行一个任务,报告它的完成百分比.在执行此操作时,我会向控制台显示一个进度条.我在调用Console.Write之前使用Console.SetCursorPosition(0, Console.CursorTop);来更新当前行,这样进度条就会相应地更新.

当我使用Windows终端在PowerShell中运行它时,它的行为恰好是我想要的.每次更新都会覆盖当前行.问题是,如果我在(传统的)conhost.exe中从PowerShell运行应用程序,它不会覆盖该行.输出为:

[        ][  0%]
[=       ][  1%]
[=       ][  2%]

...诸若此类.下面是一个完整的程序,展示了这种行为:

static void Main(string[] args)
{
    Progress<int> progress = new Progress<int>();
    progress.ProgressChanged += Progress_ProgressChanged;

    IProgress<int> reporter = progress;

    for (int i = 0; i < 100; i++)
    {
        Thread.Sleep(1000);
        reporter.Report(i);
    }
}

private static void Progress_ProgressChanged(object? sender, int e)
{
    Console.SetCursorPosition(0, Console.CursorTop);
    Console.Write(GetProgressString(e));
}

private static string GetProgressString(int progress)
{
    // Total width of the progress meter.
    // Console width minus "[][100%]".
    int width = Console.WindowWidth - 8;
    double progressDec = (double)progress / 100;
    int numChars = (int)(progressDec * width);

    StringBuilder meterBuilder = new StringBuilder();

    for (int i = 0; i < numChars; i++)
    {
        meterBuilder.Append('=');
    }

    for (int i = 0; i < (width - numChars); i++)
    {
        meterBuilder.Append(' ');
    }

    return $"[{meterBuilder}][{string.Format("{0, 3}", progress)}%]";
}

有没有其他方法可以在旧的Windows控制台主机上实现这一点?

推荐答案

您的代码可以很好地覆盖当前行--但在失败的情况下,"当前行"并不是您所认为的那样.

如果您不想将行向前移动,请不要写到最后一列,因为光标位置必须是您所写的after,并且一些终端会主动将其换到下一行.

或者,您可以在写入之前(在光标位置有机会溢出到下一行之前)保存值CursorTop.

您已经不能很好地处理任何其他并发控制台输出,因为您覆盖了当前行上的任何内容,无论它是否由进度条生成.保存您实际编写的Y坐标可能会改进这一点(但您还需要在更新进度条后恢复光标位置,否则其他输出将重复替换进度条之后的行,而不是正确累积).

Csharp相关问答推荐

应用程序启动时出现错误:操作无法同时使用表单和SON主体参数

在ASP.NET中为数据注释 Select 合适的语言

我可以 suppress 规则CS 9035一次吗?

使用C#中的Shape API从Azure目录获取所有用户

C#相同名称的枚举方法和normal方法,参数类型不同

找不到网址:https://localhost:7002/Category/Add?区域= Admin.为什么我的URL是这样生成的?area = Admin而不是/Admin/

如何在Visual Studio代码中更改大括号模式{},用于C#语言

如果属性名为xyz,我需要使用System.Text.Json修改字符串类型的值""<>

Int和uint相乘得到LONG?

使用C#HttpClient以多部分形式数据发送带有非ASCII文件名的文件的问题

如何使用MailKit删除邮箱?

Linux Docker上的.NET6在某个时间抛出后,在加密操作期间发生System.Security.Cryptography.CryptographicException:错误

什么类型的对象存储在大对象堆(LOH)中

Content WithTargetPath实际上是有效的MSBuild项吗?

当我try 在与XAMP的MySQL服务器连接的ASP.NET核心应用程序中添加迁移时出现错误

C#静态抽象属性不能被子接口覆盖

Visual Studio 17.8.0制表符自动完成问题--三缩进

仅在ASP.NETCore应用程序中的附加单独端口上公开一组终结点

如何从原始图像到新创建的图像获得相同的特定 colored颜色 ,并且具有相同的 colored颜色 量和相同的宽度和高度?

如何使用LINQ在C#中填充列表列表?