October 2007 - Posts

Tedious coding sucks. SubSonic saves lots of time. But I want it to save me more. So I've started working on a method that will fill out the controls for me so I don't have to. It's simple really. I just new() up a the model I will use and pass it to my method along with the UserControl I have my form elements in.

   1:  public void SetupForm<T>(Control form, T activeRecord ) 
   2:      where T : AbstractRecord<T> ,new()
   3:  {
   4:      TableSchema.TableColumnSettingCollection settings = activeRecord.GetColumnSettings();
   5:      foreach (TableSchema.TableColumnSetting setting in settings)
   6:      {
   7:          Control settingControl = form.FindControl(setting.ColumnName);
   8:          if (settingControl is TextBox)
   9:              ((TextBox)settingControl).Text = 
  10:                  activeRecord.GetColumnValue<string>(setting.ColumnName);
  11:          if (settingControl is DropDownList)
  12:              ((DropDownList)settingControl).SelectedValue = 
  13:                  activeRecord.GetColumnValue<string>(setting.ColumnName);
  14:      }
  15:  }

The key thing is to make sure you have called EnsureChildControls() before calling this method.

So in my control the code looks like

   1:  int issueId = SubSonic.Sugar.Web.QueryString<int>("issue");
   2:  if (issueId != 0)
   3:  {
   4:      EnsureChildControls();
   5:      Issue issue = new Issue(issueId);
   6:      //BasePage inherits from System.Web.UI.Page
   7:      BasePage.SetupForm(this, issue);
   8:  } 

Now this is pretty rough and more than anything a proof of concept so your mileage may vary. But I figure this is a good place to start

kick it on DotNetKicks.com

I've changed this a bit due to some comments

   1:  enum Directions
   2:  {
   3:      Up,
   4:      Down,
   5:      Left,
   6:      Right
   7:  }
   8:  void DoSomething()
   9:  {
  10:      
  11:      Directions currentState =(Directions) Enum.Parse(typeof(Directions), "Down"); 
  12:  }

Have you ever wanted to grab bulk data on a grid view? It's actually not that hard at all. Set the System.Web.UI.WebControls.GridView.DataKeys Property on the Grid, then on the postback event iterate over the grid like so.

   1:  foreach (GridViewRow row in gridView.Rows) 
   2:  { 
   3:      DataKey data = gridView.DataKeys[row.RowIndex]; 
   4:      int Id = (int)data.Values["Id"]; 
   5:      TextBox myControl = row.FindControl("mycontrol") as TextBox; 
   6:      //do something with the data
   7:  } 

And on your GridView add the DataKeys Property

   1:  <asp:GridView ID="myGrid" runat="server" 
   2:       DataSourceID="myDataSource"
   3:       DataKeyNames="Id" >

I think SubSonic is simply amazing. It has saved me so much time and effort of writing. One little trick that it's got is the LoadFromPost method the Models inherit from the SubSonic.AbstractRecord<T> class.

What LoadFromPost does is iterate over the the Request.Forms collection and matches the name of the form element with the corresponding  property for your Model. So what that means is no more of this.

 1: Product prod = new Product();
 2: prod.Name = name.Text;
 3: ....//More code setting the properties based on the form
 4: prod.Save

So all you now have to do is this

 1: Product prod = new Product
 2: prod.LoadFromPost();//this loads up all the properties.
 3: prod.Save();

Anything that saves time is a good thing, and nothing sucks more than writing tedious databinding code. Another advantage is that you don't need to use Server controls just plain html tags so you don't have to worry about ASP.Net adding all the extra naming container bits as well and that'll play nicely with any JavaScript or CSS that uses the id of an html tag.

kick it on DotNetKicks.com

I recently updated an application to the latest version of the Ajax Control Toolkit and my AutoComplete Extender broke. It was returning the list fine. but in the dropdown the only values showed were undefined. Not cool. But after some research I changed the web service that returns the values to use the new AutoComplete Item

First Version

 

 1: [WebMethod]
 2: public string[] AutoComplete( string prefixText, int count )
 3: {
 4:  List<string> results = new List<string>(); 
 5:  IDataReader reader = DataLayer.AutoCompleteLookup(prefixText).GetReader(); 
 6:  while (reader.Read())
 7:  {
 8:  results.Add(reader[0].ToString());
 9:  }
 10:  
 11:  return results.ToArray();
 12: }

That worked fine, and I have a feeling that if the service wasn't returning numeric values like 01-145 that it might still be fine, but the service was returning values like 01-145 so I had to do this

 1: [WebMethod]
 2: public string[] AutoComplete( string prefixText, int count )
 3: {
 4:  List<string> results = new List<string>(); 
 5:  IDataReader reader = DataLayer.AutoCompleteLookup(prefixText).GetReader(); 
 6:  while (reader.Read())
 7:  {
 8:  results.Add(
 9:  AutoCompleteExtender.CreateAutoCompleteItem
 10:  (
 11:  reader[0].ToString(), 
 12:  reader[0].ToString()
 13:  )
 14:  );
 15:  }
 16:  return results.ToArray();
 17: }

After that changed the AutoComplete worked again.

Now that got me wondering what I could do with the AutoComplete Item that comes back. So I found a post by Phani Raj. The Extender Control has a property OnClientItemSelected (actually the extender has 9 OnClient events) so you could do something like this.

 1: <ajax:AutoCompleteExtender ID="AutoComlete" runat="server"
 2:  TargetControlID="lookupBox"
 3:  ServicePath="~/services/Lookup.asmx" 
 4:  ServiceMethod="AutoComplete" 
 5:  OnClientItemSelected="AutoComlete_Selected" />
 6:  
 7: <script language="javascript">
 8:  function AutoComlete_Selected( source, eventArgs ) {
 9:  $get("hiddenField").value = eventArgs.get_value();
 10:  //eventArgs also has .get_text() 
 11:  }
 12: </script>

Hope this helps someone

More Posts