views:

166

answers:

3

I have a common comms library that i have written to communicate with our hardware over TCP/IP

The common library allows both the clients application and our engineer tool to share common code. The common library runs threads that need to return data back to forms.

I have some working code but I feel that there must be an easier way to do it.

This is a simplified version of what i have...

namespace EngineerTool
{

    public delegate void DelegateSearchFinished();

    public partial class MainForm : Form
    {
        public DelegateSearchFinished d_SearchFinished;
        Discover discovery;

        public MainForm()
        {
            InitializeComponent();
            discovery = new Discover(this.FinishedSearchInvoke);
            d_SearchFinished = new DelegateSearchFinished(this.FinishedSearch);
            discovery.Start();
        }

        public void FinishedSearchInvoke()
        {
            this.Invoke(this.d_SearchFinished, new Object[] {});
        }

        public void FinishedSearch()
        {
            // Search has finished here!
        }
    }
}

namespace DiscoveryTool
{
    public delegate void DelegateSearchFinished();

    public class Discover
    {
        DelegateSearchFinished _callFinished;

        public Discover(DelegateSearchFinished callFinished)
        {
            _callFinished = callFinished;
        }

        public void Start()
        {
            // starts thread and stuff
        }

        public void ThreadWorker()
        {



            _callFinished();
        }

    }
}
A: 

Take a look at the BackgroundWorker class:

BackgroundWorker Component Overview

AndrewS
i looked into BackgroundWorker but it wasnt fexible enough so i wrote my own threads...
A: 

What about creating an event on the Discover class and the Form subscribes to the event, instead of passing delegates around.

CSharpAtl
sounds like a good idea, will this be all thread safe?
yes...you subscribe based on the instantiated object. You can send back a thread identifier in the event args if you need to know "who" processed the work.
CSharpAtl
got this working perfectly
A: 

Let's say that you are performing a search that will result in a List<Customer> object. One rather straight-forward and simple approach is then to raise an event when the search is done, using a special EventArgs class carrying the result:

public class CustomerSearchEventArgs : EventArgs
{
    public List<Customer> Customers { get; private set; }
    public CustomerSearchEventArgs(List<Customer> customers)
    {
        Customers = customers;
    }
}

...in the search class:

// the parameter is there to conform to the signature of the WaitDelegate
// used when invoking the method using the ThreadPool
public void Search(object state)
{    
    List<Customer> result = new List<Customer>();
    // perform the search, populate the result list
    // call a method to raise the event
    OnSearchFinished(new CustomerSearchEventArgs(result));
}

protected void OnSearchFinished(CustomerSearchEventArgs e)
{
    EventHandler<CustomerSearchEventArgs> searchFinished = this.SearchFinished;
    if (searchFinished != null)
    {
        searchFinished(this, e);
    }
}

...and in the form:

private delegate void CustomerListHandler(List<Customer> customers);

private void StartSearch()
{
    CustomerSearch search = new CustomerSearch();
    search.SearchFinished += new EventHandler<CustomerSearchEventArgs>(Search_SearchFinished);
    ThreadPool.QueueUserWorkItem(search.Search);
}
private void Search_SearchFinished(object sender, CustomerSearchEventArgs e)
{
    SearchFinished(e.Customers);
}

private void SearchFinished(List<Customer> list)
{
    if (this.InvokeRequired)
    {
        // the method is NOT executing on the UI thread; we
        // need to invoke it on the right thread
        this.Invoke(new CustomerListHandler(SearchFinished), list);
    }
    else
    {
        lstCustomers.Items.Clear();
        lstCustomers.DisplayMember = "Name";
        lstCustomers.Items.AddRange(list.ToArray());
    }
}
Fredrik Mörk
i managed to do it without having to have an EventArgs class.i have: public delegate void NegotiateStatus(string status); public event NegotiateStatus OnNegotiateStatus;then i can just call OnNegotiateStatus("string")then in my form i just have conNeg.OnNegotiateStatus += new NegotiateConnection.NegotiateStatus(this.NegotiateStatus);