Scripts are usually safe
Posted By: nicocrm on February 24th, 2011 in Uncategorized
No Gravatar

I think I just found the most awesome warning message ever. I am going to write all my dialogs like this too now. “Deleting an account is usually safe. Are you sure you wish to delete this account?”

Scripts are usually safe


Confirmation prompt in SalesLogix Web
Posted By: nicocrm on January 6th, 2011 in Uncategorized
No Gravatar

A lot of time in the LAN client I have some logic similar to this snippet (which updates the account manager to match the region selected by user in a picklist):

sUser = GetField("userid", "userinfo", "region = '" & Sender.Text & "'")
If sUser <> lueAccMgr.LookupID Then
  If MsgBox("Would you like to change the account manager to match selected region?", vbOkCancel) = vbOk Then
   lueAccMgr.LookupID = sUser
  End If
End If

In the web client you would want to do something like this:

IUser user = GetUserByRegion(CurrentEntity.Region);
if(user != CurrentEntity.AccountManager){
  if(PromptUserForConfirmation()){ 
    CurrentEntity.AccountManager = user;
  }
}

But how to implement the “PromptUserForConfirmation” method? You can’t do a modal dialog box from server-side code.

One method would be to implement all of the logic from client side. You can use an ajax call (maybe using sdata) to implement the “GetUserByRegion” in Javascript, and probably in this particular case it would be simple enough to be very feasible.

Sometimes there is a bit too much logic on the server side to be ported over to javascript, or you just don’t want to have to load too much logic on the client (which is often harder to maintain). In that case you can use what I call the “hidden button” trick. This keeps most of the logic on the server and separate the process in 2 steps, using a non-displayed button on the client to allow the script to “resume”. The button on the page would be something like (make sure you do “display: none”, not “Visible=false”, as the latter would prevent the button from being output on the page at all):

<asp:Button style="display:none" runat="server" id="btnConfirmRegionManagerChange" OnClick="btnConfirmRegionManagerChange_Click"/>

The code on the picklist change event would become:

// first postback, executes when the user has just made the picklist change
// (assuming the picklist is set up to autopostback)
// here we run the first part of the logic
IUser user = GetUserByRegion(CurrentEntity.Region);
if(user != CurrentEntity.AccountManager){
  // register a client script to show confirmation prompt and simulate a button click
  ScriptManager.RegisterStartupScript(this, GetType(), Guid.NewGuid().ToString(), 
   "if(confirm('Would you like to change the account manager to match selected region?')) " + 
     "$('#" + btnConfirmRegionManagerChange.ClientID + "').click();", true);     
}

And finally the handler for the btnConfirmRegionManagerChange click would take care of the second part of the process:

// Here we just call the GetUserByRegion method again... 
// If there was a lot of processing involved you could cache the result from the previous postback
// into a hidden field or a ViewState variable
IUser user = GetUserByRegion(CurrentEntity.Region);
CurrentEntity.AccountManager = user;

This way you have a bit of extra work, but the basic structure of the code remains the same so it is still easy to follow. I should mention I have not actually tried the code snippets above so if you copy / paste and find any typo please let me know.

Hope this helps!


Free Amazon EC2 instance
Posted By: nicocrm on November 21st, 2010 in Uncategorized
No Gravatar

Throwing it out there as I did not know about it – Amazon is offering a free tier for its Elastic Cloud services. It’s available at http://aws.amazon.com/free. Only for the Linux “micro” instance, and only for a year, but it’s still very nice for me (mainly so I can avoid problems like waiting for 2 weeks for a new fan). The one thing that I found was rather dumb is I had to create a new account for it as it was reserved to new users and I had previously used Amazon S3 on my main account (why ever do people make these “new customers only” offers – are they really trying to alienate the existing customer base?). Also be careful not to make the same mistake I made – this pricing only applies to the “basic” Linux install, not the Suse or CentOS builds.

Also not sure when they added the Windows “Micro” instance – not part of this free tier but at $.03/hr that would be very economic way to run a small site if you need a bit more control than with an ASP.NET host (no, I very much doubt you can run SalesLogix on it, hah). It comes off quite a bit cheaper than MS Azure and I am not too sure what Azure buys you for the extra cost. Will be an interesting competition to watch in the coming months.


Microsoft Visual Studio is waiting for an operation to complete
Posted By: nicocrm on August 7th, 2010 in Uncategorized
No Gravatar

This is not an uncommon message… but I hope this could help someone who is confronted with the same issue I was.

I found I was getting the error every time I started Visual Studio in the morning, with Visual Studio hanging for a looong time… but not in the afternoon… crazy uh? The difference is in the morning I connect to my workstation via remote desktop… and usually in the afternoon I am physically at the keyboard. It turns out the delay was caused by the remote desktop clipboard helper… an application called rdpclip.exe. Killing the application solved the problem (though it does prevent pasting via remote desktop, obviously, but I can live without that)


SLX Generic “Disable Form” function
Posted By: nicocrm on April 14th, 2010 in Uncategorized
No Gravatar

This is a generic function to enable / disable all controls on a form from server-side, except for buttons. Call as LockForm(this, true) or LockForm(this, false). Watch out as values will be persisted between postbacks (e.g. when browsing through SalesLogix entities). Also, it won’t go through a main view tab.

/// <summary>
/// Enable / disable all controls on the form
/// </summary>
/// <param name="islocked"></param>
private void LockForm(Control parent, bool islocked)
{
    foreach (Control c in parent.Controls)
    {
        if (c is IButtonControl || c is SmartPartToolsContainer)
            continue;
        if (c.Controls.Count > 0)
            LockForm(c, islocked);
        
        PropertyInfo pr = c.GetType().GetProperty("ReadOnly");
        if (pr != null)
        {
            pr.SetValue(c, islocked, null);
        }
        else
        {
            pr = c.GetType().GetProperty("Enabled");
            if (pr != null)
            {
                pr.SetValue(c, !islocked, null);
            }
        }
    }
}