tags:

views:

204

answers:

4

Greetings,

I have a method to capture packets. After capturing I want to add each packet as a row in listview in real time so as soon as I capture packet I want to add it to the list view.

The problem that when I use items.Add() I will get overload argument error. Please advise!!

Here is my code:

private void packetCapturingThreadMethod() {

        Packet packet = null;
       int countOfPacketCaptures = 0;
        while ((packet = device.GetNextPacket()) != null)
            {

            packet = device.GetNextPacket();
            if (packet is TCPPacket)
                {
                TCPPacket tcp = (TCPPacket)packet;
                myPacket tempPacket = new myPacket();

                tempPacket.packetType = "TCP";
                tempPacket.sourceAddress = Convert.ToString(tcp.SourceAddress);
                tempPacket.destinationAddress = Convert.ToString(tcp.DestinationAddress);
                tempPacket.sourcePort = Convert.ToString(tcp.SourcePort);
                tempPacket.destinationPort = Convert.ToString(tcp.DestinationPort);
                tempPacket.packetMessage = Convert.ToString(tcp.Data);
                packetsList.Add(tempPacket);


                string[] row = { packetsList[countOfPacketCaptures].packetType, packetsList[countOfPacketCaptures].sourceAddress, packetsList[countOfPacketCaptures].destinationAddress, packetsList[countOfPacketCaptures].sourcePort, packetsList[countOfPacketCaptures].destinationPort, packetsList[countOfPacketCaptures].packetMessage };
                try {


                    listView1.Items.Add(packetsList[countOfPacketCaptures].packetType, packetsList[countOfPacketCaptures].sourceAddress, packetsList[countOfPacketCaptures].destinationAddress, packetsList[countOfPacketCaptures].sourcePort, packetsList[countOfPacketCaptures].destinationPort, packetsList[countOfPacketCaptures].packetMessage)

                    ; countOfPacketCaptures++;
                lblCapturesLabels.Text = Convert.ToString(countOfPacketCaptures);}
                catch (Exception e) { }

                }
            else if (packet is UDPPacket)
                {

                UDPPacket udp = (UDPPacket)packet;


                myPacket tempPacket = new myPacket();

                tempPacket.packetType = "UDP";
                tempPacket.sourceAddress = Convert.ToString(udp.SourceAddress);
                tempPacket.destinationAddress = Convert.ToString(udp.DestinationAddress);
                tempPacket.sourcePort = Convert.ToString(udp.SourcePort);
                tempPacket.destinationPort = Convert.ToString(udp.DestinationPort);
                tempPacket.packetMessage = Convert.ToString(udp.Data);
                packetsList.Add(tempPacket);
                string[] row = { packetsList[countOfPacketCaptures].packetType, packetsList[countOfPacketCaptures].sourceAddress, packetsList[countOfPacketCaptures].destinationAddress, packetsList[countOfPacketCaptures].sourcePort, packetsList[countOfPacketCaptures].destinationPort, packetsList[countOfPacketCaptures].packetMessage };
                try { dgwPacketInfo.Rows.Add(row);
                countOfPacketCaptures++;
                lblCapturesLabels.Text = Convert.ToString(countOfPacketCaptures);
                }
                catch (Exception e) { }


                }


            }
        }
+5  A: 

That's because the Add method does not accept a random sequence of parameters. It can accept parameters only of the types mentioned here:

http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.listviewitemcollection.add.aspx

logicnp
+3  A: 

In addition to what logicnp said, my guess is that you are running your while loop on a separate thread (because otherwise it would block the UI thread).

Once you fix the initial issue, you will need to properly update the UI elements across thread boundaries.

Here's a tutorial that explains the problem and solutions.

Eric J.
A: 

Also once you get it working, refactor to create a class which inherits from listview and add your own overloaded Add methods which takes your full-blown objects of whatever classes and adds them to the listview appropriately - this will save you some code duplication and make your code a lot cleaner, more readable and maintainable.

Cade Roux
Definitely take the spirit of this advice and run with it but please don't apply it literally. Inheritance should not be used to specialize behavior; it should be used to create variation behind an abstraction.Refactor the code into another object that uses a reference to the list view. In a case like this, I would suggest creating a proxy that holds a reference to the target list view and encapsulates the behaviors required to adapt your data into the view. Then consider breaking that into two classes: one for threading and one for these specific data.
@MaxGuernseyIII Are you advocating adaptors of the form TCPAdaptor<ListView, TCPPacket>, UDPAdaptor<ListView, UDPPacket>?
Cade Roux
If you like. I'm just advocating /not/ inheriting from ListView but still encapsulating the "render to a ListView" logic.
@MaxGuernseyIII, Because I usually subclass all third party controls to provide application-level common base functionality, I would typically make MyTCPListView inherit from MyListView (which inherits from ListView) and implement IRender<TCPPacket> which would be an interface I would define all these renderers to conform to.
Cade Roux
What is the motivation to inherit from the third party class rather than proxy it?
@MaxGuernseyIII Proxying ListView (and large GUI controls, in general) is rather huge. If you know of an easy way which preserves all the designer and everything, I'd be interested. I have proxied some controls which do not have designers and in which the application has limited interaction (i.e. Microsoft Research's Automatic Graph Layout control). Typically I want to add things to help standardize the control more easily. Thus all forms in my app will derive from MyForm which offers standard services, which my app wants to consume. Much easier to do this from the start, too.
Cade Roux
The proxy doesn't have to have the interface of the entire control, it just has to add the optional behavior required by certain clients. In fact, in this case, the clients don't even need to see anything other than that behavior which is added by the client. Look at the code I posted in my answer above to see how easily this sort of thing can be done.
+2  A: 

This is really just a synthesis of the advice you've been given thus far.

The points that have been given so far are:

  1. Convert your data into a format that ListView can understand.
  2. Separate concerns to make testing and maintenance easier.
  3. Understand and work with the WinForms threading model.

Code follows:

public partial class Form1 : Form
{
  private readonly Device _device;
  private readonly PacketBinder _packetBinder;

  public Form1()
  {
    InitializeComponent();
    _device = Device.GetInstance();
    _packetBinder = PacketBinder.GetInstance(listView1);

    var thread = new Thread(WritePackets);
    thread.IsBackground = true;

    thread.Start();
  }

  private void WritePackets()
  {
    Packet packet = null;
    int countOfPacketCaptures = 0;
    while ((packet = _device.GetNextPacket()) != null)
    {
      packet = _device.GetNextPacket();
      MyPacket tempPacket = null;

      if (packet is TCPPacket)
      {
        TCPPacket tcp = (TCPPacket)packet;
        tempPacket = MyPacket.GetInstance();

        tempPacket.PacketType = "TCP";
        tempPacket.SourceAddress = Convert.ToString(tcp.SourceAddress);
        tempPacket.DestinationAddress =
          Convert.ToString(tcp.DestinationAddress);
        tempPacket.SourcePort = Convert.ToString(tcp.SourcePort);
        tempPacket.DestinationPort = Convert.ToString(tcp.DestinationPort);
        tempPacket.PacketMessage = Convert.ToString(tcp.Data);
      }
      else if (packet is UDPPacket)
      {

        UDPPacket udp = (UDPPacket)packet;


        tempPacket = MyPacket.GetInstance();

        tempPacket.PacketType = "UDP";
        tempPacket.SourceAddress = Convert.ToString(udp.SourceAddress);
        tempPacket.DestinationAddress =
          Convert.ToString(udp.DestinationAddress);
        tempPacket.SourcePort = Convert.ToString(udp.SourcePort);
        tempPacket.DestinationPort = Convert.ToString(udp.DestinationPort);
        tempPacket.PacketMessage = Convert.ToString(udp.Data);
      }

      if (tempPacket != null)
      {
        _packetBinder.AddPacketToView(tempPacket);
      }
    }
  }
}

internal class Device
{
  private Device() { }

  internal static Device GetInstance()
  {
    return new Device();
  }

  internal Packet GetNextPacket()
  {
    var random = new Random();
    var coin = random.Next(2);

    Thread.Sleep(500);

    if (coin == 0)
    {
      return new TCPPacket()
      {
        Data = GetRandomString(random),
        SourceAddress = GetRandomString(random),
        SourcePort = random.Next(),
        DestinationAddress = GetRandomString(random),
        DestinationPort = random.Next()
      };
    }
    else
    {
      return new UDPPacket()
      {
        Data = GetRandomString(random),
        SourceAddress = GetRandomString(random),
        SourcePort = random.Next(),
        DestinationAddress = GetRandomString(random),
        DestinationPort = random.Next()
      };
    }
  }

  private string GetRandomString(Random random)
  {
    var bytes = new byte[16];
    random.NextBytes(bytes);

    return Convert.ToBase64String(bytes);
  }
}

internal class MyPacket
{
  private MyPacket() { }

  internal static MyPacket GetInstance()
  {
    return new MyPacket();
  }

  internal string PacketType { get; set; }
  internal string SourceAddress { get; set; }
  internal string DestinationAddress { get; set; }
  internal string SourcePort { get; set; }
  internal string DestinationPort { get; set; }
  internal string PacketMessage { get; set; }
}

internal class ThreadSafeListViewMutator
{
  private readonly ListView _target;

  private ThreadSafeListViewMutator(ListView target)
  {
    _target = target;
  }

  internal static ThreadSafeListViewMutator GetInstance(ListView target)
  {
    return new ThreadSafeListViewMutator(target);
  }

  internal void AddListViewItem(ListViewItem listItem)
  {
    Action action = () => _target.Items.Add(listItem);
    Delegate asDelegate = action;
    var handle = _target.BeginInvoke(asDelegate);
    _target.EndInvoke(handle);
  }
}

internal class PacketBinder
{
  private readonly ThreadSafeListViewMutator _target;

  private PacketBinder(ListView target)
  {
    _target = ThreadSafeListViewMutator.GetInstance(target);
  }

  internal static PacketBinder GetInstance(ListView target)
  {
    return new PacketBinder(target);
  }

  internal void AddPacketToView(MyPacket tempPacket)
  {
    var listItem = new ListViewItem() { Text = tempPacket.PacketType };

    AddSubItem(listItem, "From", tempPacket.SourceAddress + ":"
      + tempPacket.SourcePort);
    AddSubItem(listItem, "To", tempPacket.DestinationAddress + ":"
      + tempPacket.DestinationPort);
    AddSubItem(listItem, "Message", tempPacket.PacketMessage);

    _target.AddListViewItem(listItem);
  }

  private void AddSubItem(ListViewItem listItem, string attribute, string value)
  {
    listItem.Text = listItem.Text + @"
" + attribute + " = " + value;
  }
}

internal class Packet { }

// Are these really duplicated this way?  Seems crazy...
internal class TCPPacket : Packet
{
  internal string SourceAddress { get; set; }
  internal string DestinationAddress { get; set; }
  internal int SourcePort { get; set; }
  internal int DestinationPort { get; set; }
  internal string Data { get; set; }
}

internal class UDPPacket : Packet
{
  internal string SourceAddress { get; set; }
  internal string DestinationAddress { get; set; }
  internal int SourcePort { get; set; }
  internal int DestinationPort { get; set; }
  internal string Data { get; set; }
}