Question

I want to invoke a function with two out parameters and bool as return value. Now my problem is I see that those two parameters are changed when I debug, but still they are back to length = 0 (the way they are initialized) when the function returns.

I've seen that there's a great solution for the .net-framework 4, but unfortunaly I have to use the .net-framework 3.5.

Here's my code:

public delegate bool GetAllCheckedItemsDelegate(out int[] cTypes, out int[] cFiles);
public bool GetAllCheckedItems(out int[] cTypes , out int[] cFiles ) 
{  
    if (ListView.InvokeRequired)
    {
         cTypes = new int[0];
         cFiles = new int[0];
         return (bool)ListView.Invoke(new GetAllCheckedItemsDelegate(GetAllCheckedItems), new object[] { cTypes, cFiles });
    }
    else
    {
       cTypes = new int[ListView.CheckedItems.Count];
       cFiles = new int[ListView.CheckedItems.Count];
       for (int i = 0; i < ListView.CheckedItems.Count; i++)
       {
             // ......code......
       }
       return (ListView.CheckedItems.Count > 0);
    }
}
Was it helpful?

Solution

I do not really like "out" keyword, so what about of using a class (Row) that contains information:

using SCG = System.Collections.Generic;
using System.Linq;
public class Row {
   public int CheckedType { get; set; }
   public int CheckedFile { get; set; }
}
...
public delegate SCG.IEnumerable<Row> GetAllCheckedItemsDelegate();
public bool GetAllCheckedItems() {  
   if (ListView.InvokeRequired) {
      var rows = ListView.Invoke(new GetAllCheckedItemsDelegate(GetAllCheckedItems)
            , new object[] {});
      return rows.Count() > 0;
   } else {
      var rows = new SCG.List<Row>();
      for (int i = 0; i < ListView.CheckedItems.Count; i++) {
         // create and set row 
         var row = new Row { CheckedType = x, CheckedFile = y };
         ...
         rows.Add(row);
      }
      return rows.AsReadOnly(); 
   }
}

OTHER TIPS

     return (bool)ListView.Invoke(..., new object[] { cTypes, cFiles });

That modifies the object[] elements. C# does not provide syntax to get it to update the arguments of the method, there's an extra level of indirection that you can't bridge with code. It is up to you to copy the references back. Nothing to worry about, you are not actually copying the array content, just the references:

var args = new object[] { null, null };
var dlg = new GetAllCheckedItemsDelegate(GetAllCheckedItems);
var retval = (bool)ListView.Invoke(dlg, args);
cTypes = (int[])args[0];
cFiles = (int[])args[1];
return retval;

Nothing pretty about it of course. Do keep in mind that you are certainly doing something very unpretty, you have no guarantee whatsoever that you get the items you expect to get. This code runs at a very unpredictable moment in time, quite disjoint from the code that's running on the UI thread. If the user is busy checking items while the worker is running then you get a quite random selection. A snapshot of the list box state that very quickly turns stale.

This almost always requires you to disable the list box while the worker is running so you provide a guarantee that the result you compute matches the list. That in turn means that it is no longer useful to write this code at all, you might as well obtain the list before you start the thread. Which is the real solution.

I've found a solution that works for me. Still I'm open to different (and better) approaches if you think that this is not a good way to solve this.

public delegate bool BoolDelegate();    
public bool GetAllCheckedItems(out int[] cTypes , out int[] cFiles ) 
{
    if (ListView.InvokeRequired)
    {
          int[] cTypesHelpVar = new int[0];
          int[] cFilesHelpVar = new int[0];

          bool ret = (bool)ListView.Invoke((BoolDelegate) (() => GetAllCheckedItems(out cTypesHelpVar, out cFilesHelpVar)));

          cTypes = cTypesHelpVar;
          cFiles = cFilesHelpVar;

          return ret;
    }
    else
    {
          cTypes = new int[ListView.CheckedItems.Count];
          cFiles = new int[ListView.CheckedItems.Count];
          for (int i = 0; i < ListView.CheckedItems.Count; i++)
          {
                //.... code ....
          }
          return (ListView.CheckedItems.Count > 0);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top