Member 10014315 wrote:
Using a WinForms ContainerControl seems the most promising, but I'm currently stuck on how to detect events firing from the ListView controls within the ContainerControl.
This is really the question, which is specific enough to worth answering; and answering it can really help you.
I think you simply need an idea how to delegate events of some child controls to a parent control the way they can be handled by the users of your controls, without exposing the children themselves (which would be possible but of course would violate proper encapsulation).
The idea is simple enough, just on the example of only one event:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
public class CheckBoxCollectionEventArgs : System.EventArgs {
internal CheckBoxCollectionEventArgs(int index, CheckBox checkBox) {
this.checkBoxIndex = index;
this.checkBox = checkBox;
}
public int checkBoxIndex { get; internal set; }
public CheckBox checkBox { get; internal set; }
}
public class MyCompositeCheckBox {
List<CheckBox> checkBoxes = new List<CheckBox>();
public MyCompositeCheckBox() {
for(int index = 0; index < checkBoxes.Count; ++index) {
CheckBox checkBox = checkBoxes[index];
checkBox.CheckStateChanged += (sender, eventArgs) => {
if (CheckBoxCollectionCheckedStateChanged != null)
CheckBoxCollectionCheckedStateChanged.Invoke(
this,
new CheckBoxCollectionEventArgs(index, checkBox));
};
}
}
public System.EventHandler<CheckBoxCollectionEventArgs>
CheckBoxCollectionCheckedStateChanged;
}
[EDIT]
As you expressed some concerns about lambda, here is the anonymous method without lambda syntax:
checkBox.CheckStateChanged += delegate(
object sender,
CheckBoxCollectionEventArgs eventArgs) {
if (CheckBoxCollectionCheckedStateChanged != null)
CheckBoxCollectionCheckedStateChanged.Invoke(
this,
new CheckBoxCollectionEventArgs(index, checkBox));
};
You can use such syntax even with .NET Framework 2.0 (I don't think any earlier version could be considered seriously, but 2.0 is a decent version, when generics were introduced, as well as anonymous methods and other important stuff).
However, in this very application purpose, you don't have to understand all the power and theory of lambda, which is a whole big fundamental field of software. For this example, it's just enough to understand the syntax formally, as well as the simple case of
type inference. So, there is no much of lambda here, I used it mostly to be able to enjoy type inference: as you can see, I did not have to enter the types for
sender
and
eventArgs
parameters. Why? They are real types, exactly the same as in lambda-free version of code shown above, only the types are
inferred from — where? From the declaration of the event on the left side of '+=', that is,
System.EventHandler<CheckBoxCollectionEventArgs>
.
Maybe, it's more important to understand
closures, which is a very fundamental feature in many language, and the very fundamental phenomenon in modern (and not so modern) languages and systems. This is how you can pass those local (stack) variables to the handler, to allow the user to know the index and the instance of the check box which invoked the original event. Please see:
http://en.wikipedia.org/wiki/Closure_(computer_science)[
^].
[END EDIT]
Are you getting the idea? You pre-create some event handlers in your application (shown as one single
anonymous method,
index
is passed using
closure) and implement it using the invocation of customer-supplied event handler, not forgetting about checking it for null.
—SA