C# 如何添加具有特定文本颜色的列表框项目?

C# 如何添加具有特定文本颜色的列表框项目?,c#,wpf,listbox,C#,Wpf,Listbox,我试图从文本文件中将计算机列表添加到列表框中,并根据ping是否在计算机上成功,将其颜色设置为绿色表示成功,红色表示失败。问题是,它在所有项目上使用最后一台计算机的最后一种颜色。我相信这是因为Drawitem事件直到for循环完成后才被引发,但我想不出一种解决方法。感谢您的帮助。ping的简化代码 private logitem linez; struct logitem { public string text; public Brus

我试图从文本文件中将计算机列表添加到列表框中,并根据ping是否在计算机上成功,将其颜色设置为绿色表示成功,红色表示失败。问题是,它在所有项目上使用最后一台计算机的最后一种颜色。我相信这是因为Drawitem事件直到for循环完成后才被引发,但我想不出一种解决方法。感谢您的帮助。ping的简化代码

    private logitem linez;

    struct logitem
    {
        public string text;
        public Brush color;
    };
private void browsebutton_Click(object sender, EventArgs e)
    {
string textfile = ofd.FileName;
            if (textfile != "")
            {
                string[] lines = System.IO.File.ReadAllLines(@textfile);
                foreach (string line in lines)
                {
                    if (line != "")
                    {
                        string liner;
                        liner = line.Replace(" ", "");
                        if (ping successfull)
                        {
                        listBoxAddGreen();
                        }
                        else (ping fails)
                        {
                         listBoxAddRed();
                         }
                    }
                    changeCount();

                }
}
       public void listBoxAddGreen ()
    {
        linez.color = Brushes.Green;
        listBox1.Items.Add(linez.text);
    }
                  public void listBoxAddRed ()
    {
        linez.color = Brushes.Red;
        listBox1.Items.Add(linez.text);
    }

        private void listBox1_DrawItem(object sender,
System.Windows.Forms.DrawItemEventArgs e)
    {
        e.DrawBackground();
        Brush myBrush = linez.color;
        e.Graphics.DrawString(listBox1.Items[e.Index].ToString(),
            e.Font, myBrush, e.Bounds, StringFormat.GenericDefault);
        e.DrawFocusRectangle();
    }
如果你愿意使用ListView控件,那就很容易了。首先,将视图设置为列表:

然后,您可以创建一个通用函数,将彩色项添加到ListView中。基本上,所有这一切都是先添加项目,然后使用它的索引(这将是最后一个),或计数-1来更改前景色:

private static void AddColoredItemToListView(ListView listView, string item, Color color)
{
    listView.Items.Add(item);
    listView.Items[listView.Items.Count - 1].ForeColor = color;
}
因为您没有包含Ping方法,所以我将在这里包含一个简单的方法:

public static bool PingServer(string serverName)
{
    try { return new Ping().Send(serverName)?.Status == IPStatus.Success; }
    catch { return false; }
}
现在,要调用该方法,我们只需读取服务器文件,并ping每个服务器。如果对PingServer的调用返回true,我们将颜色变量设置为绿色,否则将其设置为红色,然后调用上面创建的方法:

private void browsebutton_Click(object sender, EventArgs e)
{
    var serversFile = @"f:\public\temp\servers.txt";

    var servers = File.ReadAllLines(serversFile)
        .Where(l => !string.IsNullOrWhiteSpace(l))
        .Select(l => l.Replace(" ", ""));

    foreach (var server in servers)
    {
        var color = PingServer(server)
            ? Color.Green
            : Color.Red;

        AddColoredItemToListView(listView1, server, color);
    }
}
样本输出

或者,如果愿意,您可以更改背景色:


我对它进行了一些研究,发现我们可以用列表框做同样的事情。诀窍是添加一个同时存储颜色和文本的项。你是用一个结构做的,我用的是一个类:

class ColoredItem
{
    public string Text;
    public Color Color;
};
现在,我们可以用与我的另一个答案大致相同的方式创建彩色项目,其中我们ping服务器,如果ping成功,则将颜色设置为绿色,否则将其设置为红色。我们将Text属性设置为服务器名称。请注意,我们现在直接调用listBox1.Additem,因为我们依赖自定义绘制方法来更改颜色:

public static bool PingServer(string serverName)
{
    try { return new Ping().Send(serverName)?.Status == IPStatus.Success; }
    catch { return false; }
}

private void browsebutton_Click(object sender, EventArgs e)
{
    var serversFile = @"f:\public\temp\servers.txt";

    var servers = File.ReadAllLines(serversFile)
        .Where(l => !string.IsNullOrWhiteSpace(l))
        .Select(l => l.Replace(" ", ""));

    foreach (var server in servers)
    {
        var color = PingServer(server)
            ? Color.Green
            : Color.Red;

        ColoredItem coloredItem = new ColoredItem {Color = color, Text = server};

        listBox.Items.Add(coloredItem);
    }
}
现在,在DrawItem方法中,我们尝试将该项强制转换为ColoredItem类的实例。请注意,DrawItemEventArgs包含我们正在添加的项的索引。调用DrawString方法时,现在可以使用item.Text作为服务器名称,item.Color作为笔刷颜色:

private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
    var item = listBox1.Items[e.Index] as ColoredItem;

    if (item != null)
    {
        e.Graphics.DrawString(
            item.Text, 
            e.Font, 
            new SolidBrush(item.Color), 
            e.Bounds);
    }
}
我们需要确保的另一件事是将ListBox的DrawMode设置为OwnerDrawFixed,以便调用我们的自定义绘图代码:

private void Form1_Load(object sender, EventArgs e)
{
    listBox1.DrawMode = DrawMode.OwnerDrawFixed;
}
样本输出


您是否愿意使用ListView?更改颜色更容易操作。是否已将绘图模式设置为OwnerDrawnFixed?您必须熟悉MVVM。使用它,您的任务将在几分钟内得到解决。1在视图模型中执行ping;2每个ping项目都应该有自己的视图模型,例如,带有PingOk属性的ItemVM,显示ping是否成功;3将列表框的ItemsSource绑定到ItemVM集合;4在XAML中为ListBoxItem设置触发器,根据PingOk属性的值更改前景。ListBox比ListView对您的任务更有用,所以请坚持使用此items控件。效果很好,我认为主要问题在于我的DrawItem方法,该方法通过强制转换到ColoredItem类来修复。而且,您编写代码的方式更简单、更雄辩。我现在唯一要弄清楚的是如何让结果更快地显示出来。在绘制之前,它会等待所有项目都被ping'd
private void Form1_Load(object sender, EventArgs e)
{
    listBox1.DrawMode = DrawMode.OwnerDrawFixed;
}