UITableView and UIViewcontroller as a subview

This drove me nuts for a few hours, but finally figured it out. I wanted to go ahead and share, since the web results I found when I was searching were only a few pieces here and there, and still didn't offer a final solution.

So the scenario I encountered was that I have a UIViewController that will sometimes host a subview (that is another viewcontroller) and it has a UITableView in it. The idea is that sometimes the user will tap a button, and it will add a subview of that UIViewController.

Originally I created a file that subclassed UITableViewController but I've recently found that I prefer to create UIViewControllers that have tableViews in them. They're easier to manage, and give you more control over the view. For example, you can add subviews a lot easier to a UIViewController than you can a UITableViewController.

The major issue I was having was that the UITableView did not resize properly when added as a subview. It would show some of the rows, but when the list became very long, it wouldn't let the user flick down to them. In general it was just being very strange and didn't seem to respond to any kind of frame setting.

What worked was that I created a new UIViewController (without a nib file) and implemented the following code in the loadView:

// Implement loadView to create a view hierarchy programmatically, without using a nib.

- (void)loadView

{

 

UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];

contentView.autoresizesSubviews = YES;

contentView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);

contentView.backgroundColor = [UIColor clearColor];

 

[self setView:contentView];

[contentView release];

 

tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 440) style:UITableViewStylePlain];

[tableView setAutoresizesSubviews:YES];

[tableView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];

 

 

[tableView setDataSource:self];

[tableView setDelegate:self];

 

[[self view] addSubview:tableView];

}

 

So in the loadView method, I create a UIView programmatically and set it to a full size frame. I then create a tableView and this is where I create the custom frame size that my app required. (I set it to be 440 instead of the full 480 for height). If you wanted, you could make this a variable that you initialize the UIViewController with.

If you're curious what the header file looks like, here it is:

@interface SelectPeopleViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {

 

UITableView *tableView;

}

 

@property (nonatomic, retain) UITableView *tableView;

 

By doing this, I was finally able to add the UIViewController as a subview and have it be sized properly, and the tableview finally rendered the list properly.

Hope this info helps!

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

Creating an In-App Help Menu with a .plist file

This is just a quick tutorial to help you write in an in-app help menu using a .plist file. As apps become more complicated (especially if you continue to add onto your 1.0 version with more features), it's easy to get lost in them. And a good built-in support system is appreciated by everyone. I also prefer to keep it in-app because then it's formatted properly and your users won't have to open up a browser and check, which isn't always available (or isn't always formatted properly).

Ok so I decided to use a .plist file because it'd be the easiest way to structure the document and make changes. If you wanted to get really fancy, you could host the .plist file online (and have it pull from there) so that you can make edits to it without having to re-submit the app. But that's out of the scope of this particular post.

Begin by adding the .plist to your project. You can do this easily by right clicking on your project and clicking "Add.." and then "Add New File..." :

AddNewPlist.jpg

For my plist, I decided to make the root object an array and have each object in that array be a dictionary. The reason for choosing an Array (instead of the default Dictionary) is that you can order the menu items in the file itself, without having to do any extra work once you parse it. Dictionaries result in un-ordered lists, which would be silly, since you typically would want your help menu to be organized in a logical manner (going from the most basic to advanced features, for example.) So in each dictionary, I make the first item keyed to "Title" with the value of the title that the section will have. In this manner, I can create a help menu that uses the UITableViewGroup display, and have several sections with rows in each. (Once you see some pictures, I think it'll be pretty clear.)

Here is what my final demo plist looks like. I've used my app (Compositions) as an example: PlistFile.jpg

And just as a preview of what this will end up looking like, here is the final tableview in my app:

FinalHelpTableView.jpg

Ok, so to get from the file to that screenshot is actually pretty easy. I added a new UITableViewController to my project and named it HelpViewController. I checked the box to subclass it from the UITableViewController class so that it would add in the methods that I need.

I am using a custom class that I wrote called "MenuItem". MenuItem is a generic class I use for any time I need to write a custom UITableView item list. It has the ability to chain indefinitely, so that I can easily create sections and rows with it, and also include a subtitle, description, item name, a key (which is useful when your positioning is independent of the order you add the items), etc. Here is the class definition:

As I mentioned, the subMenuItems is useful to add another array of MenuItems, so that I can easily create a hierarchy in a menu.

@interface MenuItem : NSObject {

 NSUInteger itemKey;

 NSString *itemDescription;

 NSString *itemSubtitle;

 NSMutableArray *subMenuItems;

}

@property (nonatomic, assign) NSUInteger itemKey;

@property (nonatomic, retain) NSString *itemDescription;

@property (nonatomic, retain) NSString *itemSubtitle;

@property (nonatomic, retain) NSMutableArray *subMenuItems;


Back to my HelpViewController! I create a NSMutableArray to hold my menu items:

 NSMutableArray *menuItems;

And I initialize it in my -(id)init method:

-(id)init {
 [super initWithStyle:UITableViewStyleGrouped];
 menuItems = [[NSMutableArray alloc] init];
 return self;
}


I'm choosing to create the actual menu in my ViewDidLoad method, so that if I run low on memory while I'm off the screen, I can dump it and re-create it if they come back to it.

 

Here is the code to build the menu, using my custom class and the plist file. I'll explain everything after:

-(void)loadHelpChapters {
 NSBundle *bundle = [NSBundle mainBundle];
 NSString *plistPath = [bundle pathForResource:@"HelpList" ofType:@"plist"];
 NSArray *rootArray = [[NSArray alloc] initWithContentsOfFile:plistPath];
 MenuItem *mi = nil;
 int k = 0;

 for (NSDictionary* chapter in rootArray ) {
 NSString *chapTitle = [chapter valueForKey:@"Title"];
 mi = [[MenuItem alloc] initWithKey:k andDescription:chapTitle];

 [chapter enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
 if (![key isEqualToString:@"Title"]) {

 MenuItem *subMi = [[MenuItem alloc] initWithKey:k andDescription:key andSubtitle: obj];
 [[mi subMenuItems] addObject:subMi];
 [subMi release];

 }

 }];

 [menuItems addObject:mi];

 [mi release]; mi = nil;

 k++;

 } 

 [rootArray release];

}


So what's happening here?  First I'm getting a reference to my bundle (which is your packaged app, essentially) and then getting the address of the actual .plist. I've named my HelpList so that's what's happening in line 2. I then initialize an array (which is the root object of the file) using NSArray's initWithContentsOfFile: method. That will open up the file and load all the root objects into an array.

 

Each object is now a NSDictionary, which I'm calling "chapter". I'm going to enumerate through each one and do a couple things.

First I'm going to create my section MenuItem. This is going to represent the tableView section and will have several rows in it. I ask for dictionary for the "Title" value and initialize a MenuItem with that. I am not using the key for anything in this instance (the key is just an int value) but I am adding an int k to it, just in case I ever want to use its position for anything.

Next comes the really cool part--using blocks! I need to go through the rest of the dictionary, getting everything but the Title value, to add each row to this section. I use the method -enumerateKeysAndObjectsUsingBlock which essentially goes through each dictionary item and exposes both its key and value. The key in this case is the section title, and the value in my example is the text that will appear when the user taps on the item.

For each of these enumerated dictionary values, I create a child MenuItem (called subMi) and add it to my current section MenuItem. Once added, I release it.

Once I'm done enumerating, I add this section MenuItem to my ViewController's array and release that as well, to be a good memory citizen.

Once it's done going through all the root objects, I release the rootArray object I created, freeing up that memory as well.

Now for the tableView methods. As I've mentioned, we now have a top level array of MenuItems that represents all the sections. And inside each of those, we have children MenuItems that represent rows. So this is basically an exact mirror to how tableViews work, with NSIndexPath. So it's pretty simple:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
 // Return the number of sections, which is just how many items we have in our menuItems array.
return [menuItems count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 // Return the number of rows in the section.
 // First get the top level item using section
MenuItem *mi = [menuItems objectAtIndex:section];
// Then return the number of children items from the top level one.
 return [[mi subMenuItems] count];
}

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"Cell";
 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {
 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
 // Get the top level first from the section
 MenuItem *mi = [menuItems objectAtIndex:[indexPath section]];
 // Then get the child level item from the row

 MenuItem *subMi = [[mi subMenuItems] objectAtIndex:[indexPath row]];
 [[cell textLabel] setText:[subMi itemDescription]];

 return cell;
}

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {

 // Pull from the top level to get the section title
 MenuItem *mi = [menuItems objectAtIndex:section];

 return [mi itemDescription];
}


I hope this proves helpful for someone! It might seem like a lot of work, but it's really not too bad. And as I said, now you have a code-independent method of adding and removing help items. You can do all your text editing in your .plist editor, and even put it online to update it there. You could design a system that checks for an updated help file on load (if network is present) and pull it down real quick. Plists are small text files essentially, so it would be pretty quick.

 

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

_OBJ_CLASS_$ Error (Symbol(s) missing) with Full and Free iOS apps

I am currently working on making a free version of my iOS application. I followed a fantastic tutorial a while back (http://www.bit-101.com/blog/?p=2098 ) which got me up and running with a free and regular version, sharing the same code base. This is great, because changes made will be mirrored across both versions, so you don't have the nightmare of maintaining two sets of code.

I shelved the free version for a while and then decided to come back to it, and hopefully get it out in time for 4.2's release next month. I had added several new classes and some views since the last time I built the free version and thought it would compile just fine. I was wrong!

I ran into the error with several of those new classes/views (OBJ_CLASS_$) saying the symbols were missing. I was confused, since I saw them right there in my project.

Turns out that I had to manually copy these over to the free version so that it would build along with all the other classes. XCode doesn't automatically do this if you've been working in one target and then switch to the other.

It's a simple fix though. Lets say you're getting an error that a class called "ProgramSettings" is referenced but missing. Follow these steps:

1) Find "Targets" in the left side of your Xcode window ,and expand it. You should see something like "MyApp" and "MyApp Free".

2) Expand the "MyApp Free" (or whatever version that you're getting the error in).

3) You should see lots of folders, named "Copy Bundle Resources", "Compile Sources", and "Link Binary With Libraries." You will want to find the class (ProgramSettings.m) in your project above, and simply drag and drop them into "Compile Sources", along with all the other classes.

You can repeat step #3 for what is missing. Classes go in the Compile Sources and nibs (.xib) go in the Copy Resource Bundle.

4) Clean, build and launch!

it should now be error free, assuming you had no other errors on build and in your code.

 

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

quick fix: Predicatebuilder not stacking queries issue inside for loop

I ran into this problem this morning and thought I’d share in case someone else has this issue .So I’m using PredicateBuilder with the EntityFramework and doing some pretty basic query building.

I have a list of business types that the person can select (a checkboxlist) and then it returns everything that matches. I was having an issue because it was only ever returning the businesses that matched the last item I selected—it wasn’t stacking the query at all.

Finally, I noticed what was going on. Inside my for loop:

foreach (int bTypeId in businessTypeIds)
            {
              
                businessTypes = SearchHelper.Or(businessTypes,
                    m => m.BusinessType.BusinessTypeID == bTypeId);
                businessFiltered = true;
            }

 

I was never casting bTypeId to its own variable. So if I ran a query to search for business type Ids 23 and 24, it was going through once ,and asking for == 23. Then it went through the second time, and changed the reference to both to be == 24. So the query ended up just saying does the business type equal 24 two times, instead of saying does it equal 23 or 24.

The quick fix? Add in a temporary variable and use that instead:

foreach (int bTypeId in businessTypeIds)
            {
                int tempId = bTypeId;
                businessTypes = SearchHelper.Or(businessTypes,
                    m => m.BusinessType.BusinessTypeID == tempId);
                businessFiltered = true;
            }

 

Now the tempId holds the proper Id for each type, and the query will essentially read “does it equal 23 or 24”.

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

UIViewController not being unloaded in ViewDidUnload

The past few months I've been working in objective-C since I've been doing some contract iPhone development work. I actually really like the platform. iOS is pretty fun to code for. However, it can also be incredibly frustrating--especially coming from using Visual Studio and C#.

One of the things that stopped me for a while was that I noticed that my views were not being properly unloaded in a UINavigationController setup. Whenever I popped the view, I noticed that the retain count on it stayed above 0. If I pushed on a new view, it would add 1 to it and continue until I hit a memory error.

I knew something was holding onto it but I had no idea what--I was sending release statements to everything I retained. Then after some digging around, I discovered what was going on.

By accident, I had my custom delegates I wrote marked with (retain) in the property. This lead to one of those nasty retain cycles, which means that even though I was releasing the view, the delegate still owned it.

So I changed it to (assign) and re-loaded the app. Success! It now properly completely released and deallocated the view. Here's a quick code snippet:

@property (assign) id<MyCustomDelegate> customDelegate;


Hope this helps!

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

Contract Work - Lessons Learned

I thought I would write a post of a different nature today, but still relevant to the tech world. I do a lot of contract jobs myself and really enjoy it. It's nice to keep jumping from project to project, and not having to go to an office or keep regular hours, etc. I really enjoy it. I have learned a lot in the past few years of doing it (both from experience and from help given to me from others, and the internet) so I thought I'd share some of that knowledge/experience today.

So here's my own personal "lesson's learned" that hopefully will help you if you find yourself doing contract work:

Should I take the job?

Ok, so this is the first step. Assuming you were given sufficient information about what they want, then you should really think about what you're capable of doing and whether or not you should take this job. Personally, my rule is, if I know it's possible, I'll say yes, even if I don't yet know how to do it. That's because the internet is such a great help, it would be rare to run into an issue that you can't figure out with some help. So if your clients are asking for something that you don't yet know how to program, but you know you can do it on the platform then go for it. How else are you going to learn?

Use this rule with some limitation, however. If you're really lacking the expertise or foundation in something, then unless you have tons of time to complete the project, then I wouldn't say yes. For example, I haven't personally done any 3d/openGL programming yet so I wouldn't say yes to a project that extensively uses it.

OK, so I want the job, but how much do I charge?

This part can be tricky. There is no set formula really, but I have some tips for pricing that will hopefully give you a better idea on how to confidently ask your price and have them accept. Here are some personal guidelines
  1. How much time do you have to complete the project? If it's shorter than average, then charge more. You can even make a subtle note about this (or not so subtle if they still don't get it.) If it seems too short of a time (i.e. near impossible to complete), be sure to say that. It looks bad to promise a time that you can't keep--and it makes it less likely for them to return to you for work.

  2. Your Hourly rate: How long have you been working in that language? Do you have existing projects to back you up? Or previous contacts that can vouch for your work? Are there very few people with your particular skill set? All of these things will lend themselves to setting an hourly rate. I'd also try out a quick google search of what your line of work is, to see what the industry standard is at that point in time.

    I wouldn't price too low, because you want to make your time worth it. You also want them to feel like they're paying for quality work (assuming you can deliver it :) ). Finally, think about your client. If it's a small business, then don't price it too high if you want the job. If it's an enterprise (like a Fortune company), then don't be afraid to price higher. They have the budget for it.

  3. Fixed price: If they want a fixed price project, then you need to think about how many hours it will take you to complete it and multiply it by the hourly rate you set for yourself. Then, honestly, I would add 10-20% on top of that. Why? Because nothing ever works exactly how you want it to. There are lots of times that something "trivial" is way harder than it should be, or something that "should work" doesn't for hours and it eats away at your hourly rate. I can't count the number of times I encountered a logical bug that took away an entire's day work because debuggers don't help in those cases. By adding that padding in, it's still OK to have those days where you don't get as much done as you want.

    And another useful tip: Depending on your client, and the scope, you most likely want to set that you both sign off on a specification sheet before doing any work, and that any changes will result in a re-evaulation of the price. This is to help protect you from being handed a huge new addition to the project half-way in, without any extra payment.

  4. Scope of project: Finally, is it a huge project? Is it really small/fast? This affects how much your client will be willing to pay. If it sounds big, they will be willing to pay more for it. If it seems really small, then you won't be able to get away with a large asking price (as easily).

Ok, I priced it, now what?

So now that you have the price, you want to make sure it feels justified to your client. I never set a price before I can really think about everything. For example, if you're still in your introduction phase, and they want a price, don't give one! Just comment that you will send them a proposal sheet with all the features outlined, and a price for everything. You don't want to shout out a low number and then deliver something that is way higher. You also don't want to shock them with a big number before they feel like they are getting a great product.

Make up a proposal document in a word editor. Personally, I leave the price till the very end. Why? Because by the time they reach the end, you've already discussed all the great features you plan to implement, and how it's the best product they'll ever use, etc etc...so your price comes off as a steal! If you hit them up front with a price, they will read through the document with a negative bias. Think about those commercials on TV. They always go on about their product, then at the end, ask "What would you pay for something like this? $100? $50? How about $20!!". This is not by accident.

Scenario: I finished the job way earlier than expected

You have two options then. You can either polish the hell out of the application, and even throw in a few bonus features (assuming they are in-line with the customer's needs) or you can sit and wait on it until you near your deadline.

Why don't you want to turn it in too early? Because you should treat that extra time as a surplus. If you said it is going to take you 3 weeks, and it took you only 1, you have a surplus of 2 weeks. I personally don't want to let them know that I can do a 3 week project in 1 week. Why not? Because that may not always be the case! I may later have a 3 week project that takes all 3 weeks, but if I set a precedent of delivering super early, then the pressure is on for that longer project. It also makes it harder to quote longer times if you keep delivering too early.

Feel free to deliver early, but again, don't do it too early. They may also wonder why they paid you for 3 weeks of work if you're done in 1. They may further wonder if the product sucks, or what is wrong with it, if it's done so early, etc.

I would just polish the application. Everyone loves polish in their applications. The smallest details are what make an application go from "functional" to "fantastic". And since you are still delivering on time, then they are still going to be very happy with you.

Scenario: It's taking way too long to finish this, and the deadline is nearing/here!

So this is not a fun scenario to be in, but it'll happen. Sometimes the scope of the project gets out of hand. The best policy here is OPENNESS/HONESTY. Tell them that the project is taking longer than expected, and give a reasonable time for when you think you'll have it done. I typically explain it in a way that makes it sound like it isn't something that I did wrong, but it's just something about the nature of the project.

This really goes for any scenario, to be honest. Just continue to stay open and communicative about your progress. This doesn't mean that you should email them every five minutes (unless they want you to), but it does mean that maybe every few days or once a week, give them an update on where you're at, and what's next. They'll be happy to know they are paying for progress, and it'll make it easier to ask for an extension when something goes wrong, because they know that you've been working on it all along.

Final tips and thoughts:

In general, contract work is really fun and rewarding. It's nice to learn new things all the time, as mandated by the project ,and to challenge yourself to do things you may not have done before. The key is to build a great relationship with your clients for future work, and for recommendations. I am always very honest with them and I never promise something I can't deliver. Again, under promise, over deliver!

I hope this has proved helpful!

Cheers,
samerpaul

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

Delegates: A Practical Understanding

It's been a while since I have written on this blog, and I'm planning on reviving it this summer, since I have more time to do so again.

I've also recently started working on the iPhone platform, so I haven't been as busy in .NET as before.

In either case, today's blog post applies to both C# and Objective-C, because it's more about a practical understanding of delegates than it is about code. When I was learning coding, I felt like delegates was one of the hardest things to conceptually understand, and a lot of books don't really do a good job (in my opinion) of explaining it. So here's my stab at it.

A Real Life Example of Delegates

Let's say there are three of you. You, your friend, and your brother. You're each in a different room in your house so you can't hear each other, even if you shout.

1)You are playing a computer game
2) Friend is building a puzzle
3) Brother is napping

Now, you three are going to stay in your room but you want to be informed if anything interesting is happening to the one of you. Let's say you (playing the computer game) want to know when your brother wakes up.

You could keep walking to the room, checking to see if he's napping, and then walking back to your room. But that would waste a lot of time / resources, and what if you miss when he's awake before he goes back to sleep? That would be bad.

Instead, you hand him a 2-way radio that works between your room and his room. And you inform him that when he wakes up, he should press a button on the radio and say "I'm awake". You are going to be listening to that radio, waiting for him to say he's awake. This, in essence, is how a delegate works.

You're creating an "object" (the radio) that allows you to listen in on an event you specify. You don't want him to send any other messages to you right now, except when he wakes up. And you want to know immediately when he does, so you can go over to his room and say hi. (the methods that are called when a delegate event fires). You're also currently specifying that only you are listening on his radio.

Let's say you want your friend to come into the room at the same time as you, and do something else entirely, like fluff your brother's pillow. You will then give him an identical radio, that also hooks into your brother's radio, and inform him to wait and listen for the "i'm awake" signal.

Then, when your brother wakes up, he says "I'm awake!" and both you and your friend walk into the room. You say hi, and your friend fluffs the pillow, then you both exit.

Later, if you decide you don't care to say hi anymore, you turn off your radio. Now, you have no idea when your brother is awake or not, because you aren't listening anymore.

So again, you are each classes in this example, and each of you have your own methods. You're playing a computer game (PlayComputerGame()), your friend is building a puzzle (BuildPuzzle()) and your brother is napping (Napping()).

You create a delegate (ImAwake) that you set your brother to do, when he wakes up. You listen in on that delegate (giving yourself a radio and turning it on), and when you receive the message, you fire a new method called SayHi()). Your friend is also wired up to the same delegate (using an identical radio) and fires the method FluffPillow().

Hopefully this makes sense, and helps shed some light on how delegates operate. Let me know! Feel free to drop me a line at Twitter (preferred method of contact) here: samerabousalbi


  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

QuickTip: Getting ItemIndex from ListView_Command event

Just a quick tip today, for something that I use often, and maybe others are wondering what’s the fastest way to figure out what item is actually calling the command.

 

So for our ListView_Command method, we have a “ListViewCommandEventArgs” parameter, which exposes the following properties;

 

image

So we can get to the Item, but that doesn’t really help us figure out what Item is actually calling the command. Easy enough. I’ll need to use e.Item to get to the index.

First I’ll make it into a ListViewDataItem, since in this case, I know it will be one (The command can’t come from an EmptyItem or InsertItem in my example.). You can always program in an If check to avoid casting incorrectly.

Here’s where I’m at now:

 

image

 

ListViewDataItem exposes some properties that a regular ListViewItem does not have. The ones of interest:

image

Great! Now we know the DataItemIndex, which we can use for whatever reason you might need. It’s typically useful for figuring out dataKeys for that item. For example, now I can do this:

image

 

I know exactly what the Item is, and I can gain really easy access to any DataKeys I might have set for that item, such as a primary key, a timestamp column, etc.

 

Hope this helps!

Cheers

samerpaul

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

Dynamically Adding Web User Controls and Accessing Their Properties by Using Inheritance

So I came up with a way that I could finally dynamically load user controls, and access properties from them that I need for them to work. Here’s my post!

The Problem:

Web User Controls (.ascx files) are fantastic, because they are a breeze to set up, you can add properties, and then be on your way. They’re especially useful for controls that you really only need to use in 1 spot in the program, so it’s really hard to justify turning them into server controls.

Their biggest downside is that when you want to dynamically add them to your page, using LoadControl(“”), you have to load them as a (WebUserControl) or (Control), neither of which is useful for getting access to any custom properties you may have added.

My Idea:

In the application I’m currently working on, I have a series of controls I am working on that are “preview” listviews. They will pop-up dynamically when a user clicks an item, and they will allow them to preview the item in full detail.

The control, which is a ListView + ObjectDataSource has a property called “RecordId” that I use to set the defaultValue of my select parameters in my ObjectDataSource. I’m doing this because I want my method to only return 1 record, but as an IEnumerable, for easier databinding purposes.

Here’s the get{ } set { } of RecordId:

 

image

 

So you can see I’m simply setting the default value of the select parameter (in this case, the only select parameter):

image

So what happens when I dynamically load this control? Here’s the issue:

image

No RecordId in the intellisense! And if I try to compile it, it won’t work because the compiler wont let it build since it doesn’t think there is a property called RecordId.

The Solution:

Since I am going to have a whole slew of controls that require me passing in a RecordId, I came up with the idea of using inheritance to solve the problem. I created an abstract class that Inherits from a UserControl class and then added a property called RecordId:

image

So now, in my user control that I spoke of earlier, I will override the RecordId. Here’s the full code:

I have my user control inherit from my new abstract class, which inherits from a UserControl:

image

 

And I override the RecordId so that it’s specific to this control, and gets/sets the defaultValue of my select parameter:

 

image

 

So now, back in the dynamic loading page, I will cast my LoadControl(“”) to a “RecordIdUserControl” and I’ll have access to RecordId!

image

Fantastic! As you can see, I’m in the process of setting it to a local variable called “recordId”, which I get from a control on the page that indicates what record to load.

 

Conclusion:

Hopefully this helps others out there that are looking to still use a user control, but to have the added power of accessing its properties, even when you’re loading it dynamically.

Cheers!

samerpaul

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

Quick Tip: Custom Paging with Extra Parameters in the Method

I don’t know why it never occurred to me to try this, but I wanted to write this quick post regarding this little tidbit of information because others might have been wondering the same thing as me.

I described how I use paging using the ObjectDataSource and LINQ on this post:

http://geekswithblogs.net/samerpaul/archive/2009/07/29/tutorial-paging-with-linq-and-objectdatasource.aspx

So what if you want to page some data that also includes extra parameters? For example, lets say I have a web app that allows users to create several blogs that each have their own entries. I want to be able to page those blog entries, and I want to select them for only a certain blog Id (from a drop down or a query string, or session value, etc.)

It’s pretty straight forward as to how to do that:

Step 1: Write Two methods in your ClassName.cs file (in the example, Blog.cs)

This is again very similar to my example linked above. I would write a method that I call SelectPagedRecords (you can call it whatever you’d like) and I would have the first two parameters be startRowIndex and maximumRows. I’d add in a third parameter called blogId, which is the value I pass in using my ObjectDataSource. Here’s the method signature for this one:

[DataObjectMethod(DataObjectMethodType.Select)]
public IEnumerable<BlogEntry> SelectPagedRecords(int startRowIndex, int maximumRows, int blogId)
{

}

Or an image if it helps you see it better:

image

It’s underlined red since I don’t return anything yet. That’s the next step.

I would open up a dataContext (somethingDataContext db = new somethingDataContext();) and then return all the blog entries where their blogID_FK is equal to the blogId in the parameter, and skip the startrowindex, and take the maximumRows. It’d look like this:

return db.BlogEntries
                .Where(m => m.BlogID_FK == blogId)
                .Skip(startRowIndex)
                .Take(maximumRows);

 

The other method to write is the GetRecordCount method. We can’t just use a GetRecordCount() because that would return the count of all blog entries, which we don’t want. We want to return the count of only the blog entries for a certain BlogId. You guessed it, we’d write in a parameter. It would look like this:

image

Inside, the method would return the count for all the entries of a certain BlogId:

return db.BlogEntries
               .Where(m => m.BlogID_FK == blogId)
               .Count();

 

Step 2: Creating the ObjectDataSource

Not much changes here. We’d drop in our ListView (or whatever databinding control you want to use), and configure it. It will prompt for a data source, and we can create a new one, and select ObjectDataSource.

You’ll select BlogEntries as your data type, and select “SelectPagedRecords”. On the page where it asks you to select parameters, leave the startRowIndex and maximumRows blank.

For the BlogId parameter, select something that you’ll use to separate out the blog entries. I’m using a drop down in my example, so I select that as a control parameter.

Here are the key steps broken down:

Choose the proper method:

image

Leave the parameters blank except for the one you want to set. In this example, I’m setting BlogID to come from a dropdown I previously added to the page.

image

You don’t have to set a default value, but I tend to, to avoid any possible string input errors.

Final Step: Clean up the ObjectDataSource in the code

 

Switch to Source view, and you’ll notice the ObjectDataSource has this in the selectParameters:

<SelectParameters>
      <asp:Parameter Name="startRowIndex" Type="Int32" />
      <asp:Parameter Name="maximumRows" Type="Int32" />
      <asp:ControlParameter ControlID="BlogDropDownList" Name="BlogId" PropertyName="SelectedValue"
             Type="Int32" DefaultValue="0" />
</SelectParameters>

 

 

Select the first two Parameters (startRowIndex and maximumRows) and delete them. It’ll end up looking like this:

<SelectParameters>
             <asp:ControlParameter ControlID="BlogDropDownList" Name="BlogId" PropertyName="SelectedValue"
                 Type="Int32" DefaultValue="0" />
</SelectParameters>

Add in to EnablePaging=”True” and set the SelectCountMethod=”GetRecordCount”. (Or whatever you named it.) Here’s how that’ll look:

image

Assuming you set up your ListView (or whatever databound control) to enable paging, you will now be able to page through your data records as well as pass in any number of extra parameters.

 

Cheers!

samerpaul

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati