For example. Lets say we have a stackpanel on a form. Its full of both Grids and Labels. I want to loop through all the Grids and do some operation on them but leave the Lables intact. At the moment I am doing it this way.
foreach(UIElement element in m_stacker.Children)
{
Grid block = element as Grid;
if(block != null)
{
//apply changes here
}
}
So i'm using the fact that "as" returns null if it cannot cast into the required type. Is this an ok thing to do or is there a better solution to this problem?
What about OfType()?
foreach( var grid in m_stacker.Children.OfType<Grid>() ) { ... }
This will loop only over the children of type Grid, so no need to cast or check the type at all.
Yes, it's the right way to do it (considering "applying changes" will need to use the cast result).
However, if you are not going to use the cast return value, you can simply use is.
Using is and then casting again with the cast operator (parenthesis) is frowned upon.
It will work fine. What you can do is however just use "is".
foreach(UIElement element in m_stacker.Children)
{
if(element is Grid)
{
//apply changes here
}
}
If you are going to use block as a Grid then this is exactly the right way to code it.
Checking using is (to my mind) produces less readable code as illustrated in the following two bad examples:
if (element is Grid)
{
Grid block = element as Grid;
// Do stuff
}
if (element is Grid)
{
Grid block = (Grid)element;
// Do stuff
}
Don't do either of these.
You're saying if element is a grid then cast it.
Related
I have two radio buttons in CriminalityInformationFormViewDisposal and I'm finding this controls dynamically as follows
var siaHasConvictions =
((RadioButtonList)CriminalityInformationFormViewDisposal.FindControl(ContactEntity.SIA_HASCOVICTIONS));
var siaHasOffencesAwatingTrial =
((RadioButtonList)CriminalityInformationFormViewTrial.FindControl(ContactEntity.SIA_HASOFFENCEAWAITINGTRIAL));
now on one page whenever I need to fetch the value of radio buttons i.e. whether it is selected or not every time I need to define var to find control first and then I check for its value...now it increases code line ..is there any way so I can make this findcontrol part global for that one page and then I access its value like we do for normal control ,please help me out for this,as I tried it to declare before page load,,,but gives error for gridcontrol
There is no easy way in my opinion, but this might help you not repeat the code over and over again:
private RadioButtonList SiaHasConvictions
{
get
{
return (RadioButtonList)CriminalityInformationFormViewDisposal.FindControl(ContactEntity.SIA_HASCOVICTIONS);
}
}
With this property, you can just use this.SiaHasConvictions in your code. You could optimize this by saving the reference once in a variable:
private RadioButtonList _siaHasConvictions;
private RadioButtonList SiaHasConvictions
{
get
{
if (this._siaHasConvictions == null)
{
this._siaHasConvictions = (RadioButtonList)CriminalityInformationFormViewDisposal.FindControl(ContactEntity.SIA_HASCOVICTIONS);
}
return this._siaHasConvictions;
}
}
Using the second piece of #Patrick Hofman's code is NOT guaranteed a correct behavior. If the FindControl method may return different values each time you call it, this implementation will go wrong since _siaHasConvictions won't get changed anymore once set.
However, I was inspired from #Patrick Hofman's idea of using property, you could use ?? operator in your Property to make things even easier:
private RadioButtonList _siaHasConvictions;
private RadioButtonList SiaHasConvictions
{
get { return this._siaHasConvictions ?? (this._siaHasConvictions = (RadioButtonList)CriminalityInformationFormViewDisposal.FindControl(ContactEntity.SIA_HASCOVICTIONS)); }
}
Here is the explanation and some examples of using ?? operator, and in short:
The ?? operator is called the null-coalescing operator. It returns the left-hand operand if the operand is not null; otherwise it returns the right hand operand.
I am trying to write a generic method so I can avoid code duplication. The generic method has to be able to accept one of three different grid view types however I cannot get the following cast to work at the start of the generic method;
var grid;
if (typeof(T) == typeof(GridView))
{
grid = (GridView)gridView;
}
else if (typeof(T) != typeof(BandedGridView))
{
grid = (BandedGridView)gridView;
}
else if (typeof(T) != typeof(AdvBandedGridView))
{
grid = (AdvBandedGridView)gridView;
}
else return;
How can I cast "grid" to either of the three types so I can then do something with them. I am still trying to grasp the idea and concept behind Generics.
If BrandedGridView and AdvBrandedGridView both inherit from GridView you can add a constraint to your generic
...<T> where T : GridView
If not you can use Convert.ChangeType:
Try Convert.ChangeType:
if (typeof(T) == typeof(GridView))
{
var grid = (GridView)Convert.ChangeType(gridView, typeof(GridView));
}
elseif (typeof(T) == typeof(BrandedGridView))
{
var grid = (BrandedGridView)Convert.ChangeType(gridView, typeof(BrandedGridView));
}
You want to constrain type T to something (likely GridView as 2 other types are likely derive from it) so C# knows what method the T has, otherwise it is just of type Object.
public class MyClass<T> where T : GridView
Please read article about generic on MSDN to get more details - http://msdn.microsoft.com/en-us/library/ms379564(VS.80).aspx#csharp_generics_topic4
Note: As mentioned above C# is not JavaScript and "var" does not mean "a type" it is just shorter way to declare object of type of the right side. I.e. in var my = new List() var is synonim for List.
"methods are identical except for the parameter type"
I think you should just make a new method that has the different parameter type of the view as the actual parameters. They're the ones that are different after all.
If I enter the code below, I get an error. Basically, the foreach will break when it comes across a Control that isn't a label.
foreach (Label currControl in this.Controls()) {
...
}
I have to do something like this.
foreach (Control currControl in this.Controls()) {
if(typeof(Label).Equals(currControl.GetType())){
...
}
}
can anyone think of a better way of doing it without me needing to check the type? Can I somehow get foreach to skip the objects that aren't Labels?
If you're on .NET 3.5 or newer, you can do something like this
foreach(var label in this.Controls().OfType<Label>()) {
}
OfType<T> will ignore types that cannot be cast to T. See http://msdn.microsoft.com/en-us/library/bb360913.aspx
Brian has given the most appropriate answer in terms of OfType. However, I wanted to point out that there's a better way of checking for types in cases where you do need to do it. Instead of your current code:
if(typeof(Label).Equals(currControl.GetType())){
...
}
You can use:
if (currControl is Label)
{
Label label = (Label) currControl;
// ...
}
or:
Label label = currControl as Label;
if (label != null)
{
// ...
}
Note that both of these alternatives will also include subclasses of Label, which your original code doesn't.
I need to loop through the properties of a custom object type that I'm getting back from the database and only show the columns that contain data.
This means I cannot simply bind the list of objects to the datagrid.
I don't want to loop through each object and see if the column is empty/null and determine in the UI to display it.
What I'm thinking is in my business layer before I send the object back I would send an IEnumerable back with only those columns that should be visible. Thus I was thinking of using Linq to Object to do this, but I'm not sure that would be very pretty.
Does anyone know of a solution that I could use without a ton of IF statements that I could do to check through a large object (30 or so columns) to determine what should be shown or not.
Foreach (CustomerData customerdata in Customers)
{
if (!customerdata.address.Equals(""))
{
dgvCustomerData.Column["Address"].visible = false;
}
//Continue checking other data columns...
}
I wish to avoid all of this in the UI and all the IFs...
I'm having a brain fart on this one can anyone help me?
Thanks
You could do the following to simplify it a bit
Action<T,string> del = (value,name) => {
if ( value.Equals("") ) {
dgvCustomerData.Column[name].Visible = false;
}
};
foreach ( var data in Customers ) {
del(data.address,"Address");
del(data.name, "Name");
...
}
Take a look at the .NET Reflection Libraries. You can use reflection to get ahold of all of an object's properties, and loop through them to find out if they are null or not. Then you could return a collection of KeyValuePair objects where Key = property name, and Value = true/false. You'd then use the keyvaluepairs to set column visibility...
Having a heckuva time with this one, though I feel I'm missing something obvious. I have a control that inherits from System.Web.UI.WebControls.Button, and then implements an interface that I have set up. So think...
public class Button : System.Web.UI.WebControls.Button, IMyButtonInterface { ... }
In the codebehind of a page, I'd like to find all instances of this button from the ASPX. Because I don't really know what the type is going to be, just the interface it implements, that's all I have to go on when looping through the control tree. Thing is, I've never had to determine if an object uses an interface versus just testing its type. How can I loop through the control tree and yank anything that implements IMyButtonInterface in a clean way (Linq would be fine)?
Again, know it's something obvious, but just now started using interfaces heavily and I can't seem to focus my Google results enough to figure it out :)
Edit: GetType() returns the actual class, but doesn't return the interface, so I can't test on that (e.g., it'd return "MyNamespace.Button" instead of "IMyButtonInterface"). In trying to use "as" or "is" in a recursive function, the type parameter doesn't even get recognized within the function! It's rather bizarre. So
if(ctrl.GetType() == typeToFind) //ok
if(ctrl is typeToFind) //typeToFind isn't recognized! eh?
Definitely scratching my head over this one.
Longhorn213 almost has the right answer, but as as Sean Chambers and bdukes say, you should use
ctrl is IInterfaceToFind
instead of
ctrl.GetType() == aTypeVariable
The reason why is that if you use .GetType() you will get the true type of an object, not necessarily what it can also be cast to in its inheritance/Interface implementation chain. Also, .GetType() will never return an abstract type/interface since you can't new up an abstract type or interface. GetType() returns concrete types only.
The reason this doesn't work
if(ctrl is typeToFind)
Is because the type of the variable typeToFind is actually System.RuntimeType, not the type you've set its value to. Example, if you set a string's value to "foo", its type is still string not "foo". I hope that makes sense. It's very easy to get confused when working with types. I'm chronically confused when working with them.
The most import thing to note about longhorn213's answer is that you have to use recursion or you may miss some of the controls on the page.
Although we have a working solution here, I too would love to see if there is a more succinct way to do this with LINQ.
You can just search on the Interface. This also uses recursion if the control has child controls, i.e. the button is in a panel.
private List<Control> FindControlsByType(ControlCollection controls, Type typeToFind)
{
List<Control> foundList = new List<Control>();
foreach (Control ctrl in this.Page.Controls)
{
if (ctrl.GetType() == typeToFind)
{
// Do whatever with interface
foundList.Add(ctrl);
}
// Check if the Control has Child Controls and use Recursion
// to keep checking them
if (ctrl.HasControls())
{
// Call Function to
List<Control> childList = FindControlsByType(ctrl.Controls, typeToFind);
foundList.AddRange(childList);
}
}
return foundList;
}
// Pass it this way
FindControlsByType(Page.Controls, typeof(IYourInterface));
I'd make the following changes to Longhorn213's example to clean this up a bit:
private List<T> FindControlsByType<T>(ControlCollection controls )
{
List<T> foundList = new List<T>();
foreach (Control ctrl in this.Page.Controls)
{
if (ctrl as T != null )
{
// Do whatever with interface
foundList.Add(ctrl as T);
}
// Check if the Control has Child Controls and use Recursion
// to keep checking them
if (ctrl.HasControls())
{
// Call Function to
List<T> childList = FindControlsByType<T>( ctrl.Controls );
foundList.AddRange( childList );
}
}
return foundList;
}
// Pass it this way
FindControlsByType<IYourInterface>( Page.Controls );
This way you get back a list of objects of the desired type that don't require another cast to use. I also made the required change to the "as" operator that the others pointed out.
Interfaces are close enough to types that it should feel about the same. I'd use the as operator.
foreach (Control c in this.Page.Controls) {
IMyButtonInterface myButton = c as IMyButtonInterface;
if (myButton != null) {
// do something
}
}
You can also test using the is operator, depending on your need.
if (c is IMyButtonInterface) {
...
}
Would the "is" operator work?
if (myControl is ISomeInterface)
{
// do something
}
If you're going to do some work on it if it is of that type, then TryCast is what I'd use.
Dim c as IInterface = TryCast(obj, IInterface)
If c IsNot Nothing
'do work
End if
you can always just use the as cast:
c as IMyButtonInterface;
if (c != null)
{
// c is an IMyButtonInterface
}