Open mailto links with Gmail in Chrome

Saturday, 01 May 2010 03:44 AM
by Coose

Yeah…I looked for the option in Chrome for a while.  One of the things I like about Chrome is that it has so few options.  One of the things that I don’t like about Chrome is that it has so few options.  So we have to make ALL applications open mailto: links in Gmail, not just Chrome.  So we re-associate the mailto: as we would other file extensions (.txt, etc) or COM components.

So, to use Microsoft’s disclaimer:

Modifying REGISTRY settings incorrectly can cause serious problems that may prevent your computer from booting properly. Microsoft cannot guarantee that any problems resulting from the configuring of REGISTRY settings can be solved. Modifications of these settings are at your own risk.

Now that is out of the way, the key that controls what to do when executing a “mailto:” link is:

HKEY_CLASSES_ROOT\mailto\shell\open\command

The default value is the command line that is executed.  For outlook, my command line is:

"C:\PROGRA~1\MIF5BA~1\Office12\OUTLOOK.EXE" -c IPM.Note /m "%1"

Which need to be changed to the Chrome executable:

"C:\Users\[YOUR_USERNAME_HERE]\AppData\Local\Google\Chrome\Application\chrome.exe" http://mail.google.com/mail?extsrc=mailto&url=%1

Comment on this
Development

How to Resume Suspended Workflows in .NET WF 4.0

Wednesday, 28 April 2010 12:57 AM
by Coose

So we’ve been on WF 4.0 for a while now, and we have been anxiously awaiting Dublin (AppFabric).  One of the things we really wanted out of AppFabric was the ability to resume workflows that have suspended due to unhandled exceptions.

Well, I discovered that you don’t need AppFabric.  The sql instance store already gives us that functionality…there’s just no GUI for it (that I can find).

So, start by creating the databases.  The scripts are in the framework folder:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\SQL\en\SqlWorkflowInstanceStoreSchema.sql
C:\Windows\Microsoft.NET\Framework\v4.0.30319\SQL\en\SqlWorkflowInstanceStoreLogic.sql

Now, in the service behavior for the workflow xamlx, add some entries:

          <sqlWorkflowInstanceStore connectionStringName="Workflow"

                                    hostLockRenewalPeriod="00:00:05"

                                    runnableInstancesDetectionPeriod="00:00:02"

                                    instanceCompletionAction="DeleteAll"

                                    instanceLockedExceptionAction="AggressiveRetry"

                                    instanceEncodingOption="None" />

          <workflowIdle timeToPersist="00:00:02"

                        timeToUnload="00:00:05"/>

Make sure your connection string name matches your connection string to the database tables you created from the above sql scripts.

One more configuration item to add.  The workflow control endpoint needs to be added to the xamlx workflow service.

<service name="MyWorkflowService"

         behaviorConfiguration="myServiceBehavior">

  <endpoint address=""

            binding="customBinding"

            bindingConfiguration="myBindingConfiguration"

            contract="IMyContract" />

  <endpoint address="wce"

            binding="basicHttpBinding"

            kind="workflowControlEndpoint"/>

</service>

The endpoint with ‘kind=”workflowControlEndpoint”’ (new for .NET 4.0) is the key here.  That creates the workflow control endpoint on your workflow service.

Now, after I get an exception in a workflow (and on my development machine, there has been many), the InstancesTable in the instance store contains the information we need.  Running the sql:

select Id, SuspensionExceptionName, SuspensionReason, ExecutionStatus
from [System.Activities.DurableInstancing].InstancesTable
where IsSuspended = 1

I get these records:

image

So, here I can see the suspended workflows.  What I need from here is the Id.

Now, let’s call the endpoint we created above.  It’s a piece of cake:

You need a reference to System.ServiceModel.Activities v4.  On my machine it’s found at C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.ServiceModel.Activities.dll.  This assembly contains the classes WorkflowControlEndpoint and WorkflowControlClient.

Guid workflowId = SelectWorkflowIdSomehow();

 

WorkflowControlEndpoint ep = new WorkflowControlEndpoint(

    new BasicHttpBinding(),

    new EndpointAddress("http://localhost/myWorkflowService.xamlx/wce")

);

WorkflowControlClient client = new WorkflowControlClient(ep);

client.Unsuspend(workflowId);

That’s it.  The WorkflowControlEndpoint does the work, and the workflow is unsuspended and resumed from the last persisted state before the exception happened.  Essentially, everything that happened between un-persistence and the exception is gone, and the previous state is loaded.

Cool, huh?  And you don’t even need AppFabric.  AppFabric does add a nice layer of UI for persistence and tracking, so I’m still looking forward to it! :)

Enjoy.  Or don’t.  Whatever.

Comment on this
Development
|

Can’t find media for installation package ‘Windows 7 Portable Update’

Monday, 15 March 2010 12:15 AM
by coose

I think the Zune is a far superior device to the iPod.  I have had several iPods, including the original 5GB Mac version.  The biggest reason it was a flop (in my opinion) is that it forces you into the Zune desktop software.  It’s not terrible software…ok…it is.  It can’t be used as a mass storage device, and it won’t sync with Windows Media Player.

That aside…I just ran a Windows update on my desktop that is supposed to get the Zune software to version 4.2.  It is on Windows 7 Home Premium (yeah…I’m a cheap-ass and didn’t fork out the extra $$$) 32 bit.  It tells me “Can’t find the media for installation package ‘Windows 7 Portable Device Update’.  It might be incomplete or corrupt.  Error code 0x80070002.”

zune1

Well, that’s no help.  I downloaded the full package, ran as administrator, nothing would work.  Believe it or not, running in Vista compatibility mode for the setup exe file allowed it to run.  WTF?  Test your installer much, Microsoft?

zune3

zune2

Your mileage may vary.  The scary part of this is that ActiveSync/Windows Mobility Center is gone as far as the mobile phones go.  Windows Phone 7 will be using the Zune desktop software to do local sync/backup.  You believe that?  Let’s take the biggest cause of the failure of one portable device and force it on our newest failing portable devices.  I’m keeping my fingers crossed because the Windows Phone 7 interface looks pretty cool and might allow me to jump off the Apple train and take a sledge hammer to my iPhone.

Comment on this
Development

XML Transform on Silverlight ClientConfig Files

Monday, 08 March 2010 06:56 AM
by Coose

One of the most annoying parts of developing with WCF and Silverlight is the configuration files.  I have always hated WCF configuration files.  While powerful and necessary, they are just the opposite of fun.

Using Visual Studio 10 “publish” web functionality, the Web.Config files could be transformed with Web.Release.Config.  Not bad.  Makes things a little easier.  Here’s the rub: when creating a WCF/Silverlight application, the publish transformation would transform the web.config for the server, but NOT the ServiceReferences.ClientConfig on the client.  What a PITA.

Some Microsoft blogs show that the preferred solution for this problem is to rename the published .xap file to .zip, then open the .zip file, extract the .ClientConfig file, change it, save it, re-zip it, then rename the .zip back to .xap.

Really?

After the first time, this got so cumbersome I wanted to shoot myself.  Really I wanted to shoot someone at Microsoft. :)  Anyway, Google provided a few solutions, none totally to my liking.

My boss pushed the ConfigSwitcher project on me, as in theory it seems to be what I am looking for.  Being pre-VS2010, this didn’t use the XML transformation functionality but instead used a full copy of the config file, and required another .exe that had to be copied to each machine that this would be run on.  But it is a good idea.

So my strategy is to write custom build tasks that copy the ServiceReferences.ClientConfig file to a temp file before the build, then run the XML transformation using ServiceReferences.$(Configuration).ClientConfig and output to ServiceReferences.ClientConfig.  Then after the build completes, and the transformed file has been put into the .xap file, delete the ServiceReferences.ClientConfig, and copy the original file (which is now a temp file) back.

So…

Before Build:

  • Copy ServiceReferences.ClientConfig to ServiceReferences.Build.ClientConfig
  • Transform ServiceReferences.Build.ClientConfig to ServiceReferences.ClientConfig using ServiceReferences.$(Configuration).ClientConfig

and After Build:

  • Delete ServiceReferenes.ClientConfig
  • Move ServiceReferenes.Build.ClientConfig to ServiceReferences.ClientConfig

And, I don’t want any more baggage required.  I don’t want a program that has to be installed on developer machines, and I don’t want a macro that has to be present on developer machines.  I don’t even want custom MSBuild targets installed.  So, to do this, I use the BeforeBuild and AfterBuild target overrides of the .csproj file, and I use the already present XmlTransform task of Visual Studio 10.

So, unload the project and edit the .csproj file directly.  Scroll to the bottom and there are commented out BeforeBuild and AfterBuild overrides.  Adding this snippet:

  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />

  <Target Name="BeforeBuild" Condition="Exists('ServiceReferences.$(Configuration).ClientConfig')">

    <Move SourceFiles="ServiceReferences.ClientConfig" DestinationFiles="ServiceReferences.Build.ClientConfig" />

    <TransformXml Source="ServiceReferences.Build.ClientConfig" Destination="ServiceReferences.ClientConfig" Transform="ServiceReferences.$(Configuration).ClientConfig" />

  </Target>

  <Target Name="AfterBuild" Condition="Exists('ServiceReferences.Build.ClientConfig')">

    <Delete Files="ServiceReferences.ClientConfig" />

    <Move SourceFiles="ServiceReferences.Build.ClientConfig"

          DestinationFiles="ServiceReferences.ClientConfig" />

  </Target>

 

gives me what I want.  If there is a file named ServiceReferences.Release.ClientConfig and I am building a Release version, then the transformation is run at compile time, and the transformed .ClientConfig is put into the .xap file.

Comment on this
Development
|

Service References Stopped Working in Silverlight

Friday, 15 January 2010 02:04 PM
by Coose

I have been working a Silverlight 3 project for a few weeks, and have sever service references in the project.  Everything has been working fine.  But today, after updating an EF model and the refreshing service reference, I got blank Reference.cs files.

Some of the errors and warnings were:

  • Warning    Web services at 'hou-it-dv25.ad.ursi.com' might not be accessible due to cross-domain restrictions: For more details please contact the web server administrator or press F1 after selecting this warning
  • Warning    Custom tool warning: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.   
  • Warning     Custom tool warning: Cannot import wsdl:portType
    Detail: An exception was thrown while running a WSDL import extension: System.ServiceModel.Description.DataContractSerializerMessageContractImporter
    Error: Exception has been thrown by the target of an invocation.
    XPath to Error Source: //wsdl:definitions[@targetNamespace='http://www.XXX.com']/wsdl:portType[@name='IService'] 
  • Warning    Custom tool warning: No endpoints compatible with Silverlight 3 were found. The generated client class will not be usable unless endpoint information is provided via the constructor.

Drove me nuts all day.  Finally I came across a blog post that pointed me to the answer.  I don’t know why this works, but it does.

Right click the service and select “Configure Service Reference”

servicereference

I had the “Reuse types in reference assemblies” checked, but was using the “Reuse types in all referenced assemblies”.  Just changing it to “Resuse types in specified referenced assemblies” and refreshing the service fixed the problem.

 

Go figure.

Comment on this
Development
|

Visual Studio 2010 Beta 2 Crash

Tuesday, 08 December 2009 06:43 AM
by Coose

Visual Studio 2010 Beta 2 has been running relatively good for a while now, but today, I had a crash in the WPF designer, which crashed Visual Studio, and it could not start again.

When trying to launch, I just get a “The application cannot start.” error.  No more info.  That’s it.

The problem is caused by the Visual Studio environment not saving correctly.  It saves and cleans up with the IDE closes.  In my case, the IDE didn’t close correctly, so the settings weren’t saved.

So, to fix it simply, run devenv /resetuserdata

Be warned: all of your settings are going to be erased.  Any fonts that you had configured, your MRU’s, etc.  Everything will be reset to “factory settings”.

But at least Visual Studio loads again.

Comment on this
Development

Random Photo Widget for BlogEngine.net

Sunday, 25 October 2009 03:50 PM
by Coose

Again, I’ve seen hundreds of these out there, but they all seem to work differently from what I expected.  So…I decided to write my own.  It’s really not that sophisticated here.  What I decided to do is to display a random photo pulled from the HTML of a post that has one of the specified tags.

So, in the BlogEngine “widgets” directory, create a folder called “RandomPhoto”.

Create two .ascx UserControls called “edit.ascx” and “widget.ascx”.

[more: Dude, this is long one…click here to read the full post]

Widget.ascx

This is the control that will be displayed on the widget area.  It’s simple:

    1 <%@ Control Language="C#" AutoEventWireup="true" CodeFile="widget.ascx.cs" Inherits="widgets_RandomPhoto_widget" %>

    2 <asp:Panel ID="Panel1" runat="server" HorizontalAlign="Center">

    3     <asp:HyperLink runat="server" ID="PhotoLink" NavigateUrl="#" rel="lightbox">

    4         <asp:Image runat="server" ID="PhotoImage" ImageUrl="#" />

    5     </asp:HyperLink>

    6 </asp:Panel>

Yeah, that’s it.  It’s a panel, containing a link and an image.  We will have to set the NavigateUrl of the link in codebehind, as well as the ImageUrl of the Image.

    1 using System;

    2 using System.Collections.Generic;

    3 using System.Linq;

    4 using System.Web;

    5 using System.Web.UI;

    6 using System.Web.UI.WebControls;

    7 using System.Collections.Specialized;

    8 using System.IO;

    9 using System.Linq;

   10 using Funkymule.BlogEngine.Data;

   11 using System.Configuration;

   12 using System.Globalization;

   13 using System.Text;

   14 

   15 public partial class widgets_RandomPhoto_widget : WidgetBase

   16 {

   17     protected void Page_Load(object sender, EventArgs e)

   18     {

   19     }

   20 

   21     public override string Name

   22     {

   23         get { return "RandomPhoto"; }

   24     }

   25 

   26     public override bool IsEditable

   27     {

   28         get { return true; }

   29     }

   30 

   31     public override void LoadWidget()

   32     {

   33         StringDictionary settings = GetSettings();

   34 

   35         ChangeFrequency frequency = ChangeFrequency.Always;

   36         try

   37         {

   38             if (!string.IsNullOrEmpty(settings["ChangeFrequency"]))

   39                 frequency = (ChangeFrequency)Enum.Parse(typeof(ChangeFrequency), settings["ChangeFrequency"]);

   40         }

   41         catch (FormatException)

   42         {

   43         }

   44 

   45         int dx;

   46         int dy;

   47         int rr;

   48         int rl;

   49 

   50         int.TryParse(settings["dx"], out dx);

   51         int.TryParse(settings["dy"], out dy);

   52         int.TryParse(settings["rl"], out rl);

   53         int.TryParse(settings["rr"], out rr);

   54 

   55         var tags = settings["Tags"] == null ? new string[0] : settings["Tags"].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

   56 

   57         if (tags.Length > 0) GetImage(frequency, tags, dx, dy, rl, rr);

   58     }

   59 

   60     void GetImage(ChangeFrequency changeFrequency, string[] tags, int dx, int dy, int rl, int rr)

   61     {

   62         RandomImageGenerator rig = new RandomImageGenerator();

   63         if (changeFrequency == ChangeFrequency.Daily) rig = new RandomImageGenerator(DateTime.Now.DayOfYear);

   64         else if (changeFrequency == ChangeFrequency.Hourly) rig = new RandomImageGenerator(DateTime.Now.DayOfYear ^ (int)DateTime.Now.TimeOfDay.TotalHours);

   65         else if (changeFrequency == ChangeFrequency.Minutely) rig = new RandomImageGenerator(DateTime.Now.DayOfYear ^ (int)DateTime.Now.TimeOfDay.TotalMinutes);

   66 

   67         foreach (string tag in tags) rig.Tags.Add(tag.Trim());

   68         string[] images = rig.GetRandomImage();

   69 

   70         if (images.Length == 2)

   71         {       

   72             this.PhotoImage.ImageUrl = images[1];

   73             this.PhotoLink.NavigateUrl = images[0];

   74         }

   75         if (dx > 0) this.PhotoImage.Width = dx;

   76         else if (dy > 0) this.PhotoImage.Height = dy;

   77         else this.PhotoImage.Width = 200;

   78     }

   79 }

 

Overriding the “IsEditable” makes an edit link on the widget.

Let’s examine the “LoadWidget” override:

GetSettings() on line 33 returns the settings configuration of the widget in a name/value string dictionary.

Line 35 sets the “frequency”.  I’m setting this to an enumeration that I’ve created in my blog engine assembly.

    1 public enum ChangeFrequency

    2 {

    3     Always,

    4     Daily,

    5     Hourly,

    6     Minutely

    7 }

This is an enumeration I use to determine when to change the random things on my blog, like Quote of the Day, and Random Photo.  “Always” always changes the content when the page is refreshed or a new page is rendered.  “Daily” keeps the random item the same for the entire day.  “Hourly” keeps the random item the same for the current hour, and “Minutely” keeps the item the same for the minute.  Note that this is NOT A DURATION.  i.e. “Daily” will not keep an item good for a 24 hour period.  It will keep a random item constant for the calendar day.  Once the day changes, the random item will be different.

The values dx and dy will be used for the width and height of the thumbnail.  The rr and rl are from an earlier version where I was generating a thumbnail dynamically and rotating it.  It’s not necessary now and should be removed.

The “Tags” value is a comma delimited list of tags from which images will be selected.  Once we have all of the settings parsed and default values in place of missing items, we can get the image.

The “GetImage” method creates a new “RandomImageGenerator” class.  on lines 63 – 65, you can see how the change frequency discussed above keeps a random item constant for a specified period by using a seed derived from the change frequency.  Add the tags on line 67, and get the image names on line 68.  The RandomImageGenerator class will return two strings in an array.  The first string is the URL to the thumbnail image, and the second string is the URL to the full image.

Lines 75 – 77 set the size of the image based on limiting dimensions from the settings.  The aspect ratio of the actual thumbnail will be used, so we only specify the LIMITING side.  If dx is specified, the thumbnail is constrained on the width and is allowed to grow vertically.  If dy is specified, the thumbnail is constrainted on the height, and will grow on the width.  If they are both specified, dy is ignored.

Let’s take a look at the class that gets the random image.

    1 using System;

    2 using System.Collections.Generic;

    3 using System.Linq;

    4 using System.Text;

    5 using System.Configuration;

    6 using System.Text.RegularExpressions;

    7 using System.IO;

    8 using System.Web;

    9 

   10 namespace Funkymule.BlogEngine.Data

   11 {

   12     public class RandomImageGenerator

   13     {

   14         public class DirectorySpec

   15         {

   16             public bool Deep { get; set; }

   17             public string Directory { get; set; }

   18         }

   19 

   20         private static Regex _rx = new Regex(@"<a.*?href=""(?'image'.*?)"".*?>.*?<img.*?src=""(?'thumbnail'.*?)"".*?>.*?</a>", RegexOptions.IgnoreCase | RegexOptions.Compiled);

   21         private static Random _random = new Random();

   22 

   23         private List<string> _tags = new List<string>();

   24 

   25         public IList<string> Tags { get { return _tags; } }

   26 

   27         public RandomImageGenerator()

   28         {

   29         }

   30 

   31         public RandomImageGenerator(int seed)

   32         {

   33             _random = new Random(seed);

   34         }

   35 

   36         public string[] GetRandomImage()

   37         {           

   38             return GetRandomTaggedImage();

   39         }

   40 

   41         private string[] GetRandomTaggedImage()

   42         {

   43             using (BlogEngineDataContext ctx = new BlogEngineDataContext(ConfigurationManager.ConnectionStrings["BlogEngine"].ConnectionString))

   44             {

   45                 // get a random post content that has an image referenced in it

   46 

   47                 // get post ids for all posts with the tag

   48                 var postIds = ctx

   49                     .be_PostTags

   50                     .Where(pt => this.Tags.ToArray().Contains(pt.Tag))

   51                     .Select(pt => pt.PostID);

   52 

   53                 // get a random one

   54                 for (int i = 0; i < 1000; i++)

   55                 {

   56                     Guid postId = postIds.Skip(_random.Next(0, postIds.Count())).First();

   57                     string content = ctx.be_Posts.First(p => p.PostID == postId).PostContent;

   58                     IEnumerable<Match> matches = _rx.Matches(content).Cast<Match>().Where(m => m.Success == true);

   59                     if (matches.Count() > 0)

   60                     {

   61                         Match match = matches.Skip(_random.Next(0, matches.Count())).First();

   62                         return new string[] { match.Groups["image"].Value, match.Groups["thumbnail"].Value };

   63                     }

   64                 }

   65             }

   66 

   67             return new string[0];

   68         }

   69     }

   70 }

It’s not terribly complicated.  A list of tags, a Random that is initialized from the seed specified in the constructor.  Using ADO.NET Entity Framework generated from the BlogEngine database, I am getting a list of post ids where their tag is in the list of specified tags.  Once I have a post, use the regular expression to find an image in it.  Not all posts will have an image, so I look 1000 times to try to find one.  Not elegant, but functional.  The regular expression gets the virtual path to the image, and the thumbnail. 

Note that if the post contains an image that is not a thumbnail that links to a full sized image, this method will not work for you.

 

Edit.ascx

In order to be able to specify parameters to our widget at run time through the web interface, we need to specify an edit control.  The edit control will look like this:

randomphotoconfig

Here, you enter the change frequency, comma delimited list of tags, constraining width, constraining height, and the two fields that are no longer used and need to be removed when I have time.

The ascx source looks like this:

    1 <%@ Control Language="C#" AutoEventWireup="true" CodeFile="edit.ascx.cs" Inherits="widgets_RandomPhoto_edit" %>

    2 <asp:Table runat="server" CellPadding="5">

    3     <asp:TableRow runat="server">

    4         <asp:TableCell runat="server" HorizontalAlign="Right">Change Frequency</asp:TableCell>

    5         <asp:TableCell runat="server">

    6             <asp:DropDownList ID="FrequencyBox" runat="server" />

    7         </asp:TableCell>

    8     </asp:TableRow>

    9     <asp:TableRow runat="server">

   10         <asp:TableCell runat="server" HorizontalAlign="Right">

   11             Tags:<br />

   12             <span style="font-style: italic">Separate multiple tags with a comma.</span>

   13         </asp:TableCell>

   14         <asp:TableCell runat="server">

   15             <asp:TextBox runat="server" ID="TagsTextbox" Width="200" />

   16         </asp:TableCell>

   17     </asp:TableRow>

   18     <asp:TableRow ID="TableRow1" runat="server">

   19         <asp:TableCell ID="TableCell1" runat="server" HorizontalAlign="Right">

   20             Width:<br />

   21         </asp:TableCell>

   22         <asp:TableCell ID="TableCell2" runat="server">

   23             <asp:TextBox runat="server" ID="WidthTextbox" Width="200" />

   24         </asp:TableCell>

   25     </asp:TableRow>

   26     <asp:TableRow ID="TableRow2" runat="server">

   27         <asp:TableCell ID="TableCell3" runat="server" HorizontalAlign="Right">

   28             Height:<br />

   29         </asp:TableCell>

   30         <asp:TableCell ID="TableCell4" runat="server">

   31             <asp:TextBox runat="server" ID="HeightTextbox" Width="200" />

   32         </asp:TableCell>

   33     </asp:TableRow>

   34     <asp:TableRow ID="TableRow3" runat="server">

   35         <asp:TableCell ID="TableCell5" runat="server" HorizontalAlign="Right">

   36             Left Rotation:<br />

   37         </asp:TableCell>

   38         <asp:TableCell ID="TableCell6" runat="server">

   39             <asp:TextBox runat="server" ID="LeftRotationTextbox" Width="200" />

   40         </asp:TableCell>

   41     </asp:TableRow>

   42     <asp:TableRow ID="TableRow4" runat="server">

   43         <asp:TableCell ID="TableCell7" runat="server" HorizontalAlign="Right">

   44             Right Rotation:<br />

   45         </asp:TableCell>

   46         <asp:TableCell ID="TableCell8" runat="server">

   47             <asp:TextBox runat="server" ID="RightRotationTextbox" Width="200" />

   48         </asp:TableCell>

   49     </asp:TableRow>

   50 </asp:Table>

It’s a simple table.  The codebehind:

    1 using System;

    2 using System.Collections.Generic;

    3 using System.Linq;

    4 using System.Web;

    5 using System.Web.UI;

    6 using System.Web.UI.WebControls;

    7 using System.Collections.Specialized;

    8 using Funkymule.BlogEngine.Data;

    9 using System.Globalization;

   10 

   11 public partial class widgets_RandomPhoto_edit : WidgetEditBase

   12 {

   13     protected void Page_Load(object sender, EventArgs e)

   14     {

   15         if (!IsPostBack)

   16         {

   17             int ti;

   18 

   19             FrequencyBox.DataSource = Enum.GetNames(typeof(ChangeFrequency));

   20             FrequencyBox.DataBind();

   21 

   22             FrequencyBox.SelectedValue = ChangeFrequency.Always.ToString();

   23 

   24             StringDictionary settings = GetSettings();

   25             if (settings.ContainsKey("Tags")) TagsTextbox.Text = settings["Tags"];

   26             if (settings.ContainsKey("ChangeFrequency")) FrequencyBox.SelectedValue = settings["ChangeFrequency"];

   27 

   28             if (settings.ContainsKey("dx") && int.TryParse(settings["dx"], out ti)) WidthTextbox.Text = ti.ToString(CultureInfo.InvariantCulture);

   29             if (settings.ContainsKey("dy") && int.TryParse(settings["dy"], out ti)) HeightTextbox.Text = ti.ToString(CultureInfo.InvariantCulture);

   30             if (settings.ContainsKey("rl") && int.TryParse(settings["rl"], out ti)) LeftRotationTextbox.Text = ti.ToString(CultureInfo.InvariantCulture);

   31             if (settings.ContainsKey("rr") && int.TryParse(settings["rr"], out ti)) RightRotationTextbox.Text = ti.ToString(CultureInfo.InvariantCulture);

   32         }

   33     }

   34 

   35     public override void Save()

   36     {       

   37         StringDictionary d = GetSettings();

   38         int tmp;

   39 

   40         d["Tags"] = this.TagsTextbox.Text;

   41         d["ChangeFrequency"] = FrequencyBox.SelectedValue;

   42         if (int.TryParse(WidthTextbox.Text, out tmp)) d["dx"] = tmp.ToString(CultureInfo.InvariantCulture);

   43         else d.Remove("dx");

   44         if (int.TryParse(HeightTextbox.Text, out tmp)) d["dy"] = tmp.ToString(CultureInfo.InvariantCulture);

   45         else d.Remove("dy");

   46         if (int.TryParse(this.LeftRotationTextbox.Text, out tmp)) d["rl"] = tmp.ToString(CultureInfo.InvariantCulture);

   47         else d.Remove("rl");

   48         if (int.TryParse(this.RightRotationTextbox.Text, out tmp)) d["rr"] = tmp.ToString(CultureInfo.InvariantCulture);

   49         else d.Remove("rr");

   50 

   51         SaveSettings(d);

   52     }

   53 }

Lines 19 and 20 populate the combo box with the values of the ChangeFrequency enumeration.  The text of the other controls is set from the values in the settings dictionary.

The “Save” method sets the settings values from the textboxes, etc.

That’s really all there is to it.  I’ve been using it on my blog for a while, and haven’t noticed any problems.  The regular expression might not cover all scenarios, but it should work fine for the most part.  Since my implementation uses a “RandomImageGenerator” class that is in my custom assembly, I haven’t included a project.  The functionality of that class can be merged into the widget.ascx file.  That way, you only need to place the 2 ascx files and 2 ascx.cs files in the widgets/randomPhoto directory and an assembly isn’t required.

randomphoto

Comment on this
Development

Visual Studio 2010 Beta 1 Uninstall Problem

Monday, 19 October 2009 04:09 PM
by Coose

VS2010 Beta 2 was released for MSDN subscribers today.  I’ve been waiting for a while and was real excited to get started with WF4.  Obviously beta 1 has to be uninstalled before installing beta 2.  Had a slight problem almost right away:

vs2010uninstall2

WTF? I dug up the original beta 1 disk, and still couldn’t get past this dialog.  I copied the file locally, and pointed to that folder, and still couldn’t get past this dialog.  Finally, going to the Programs and Features in the Control Panel I can see that I have the TFS Object Model component.

vs2010uninstall1

So uninstalling this component by itself succeeds.  Then, running the uninstall on Visual Studio 2010 Beta 1 works fine.

Comment on this
Development

iPhone Ringtones from MP3

Sunday, 13 September 2009 02:46 PM
by coose

I just got this iPhone, and what a hassle trying to figure out how to create my own ringtones.  I think I have it down now.  I’ll create a ringtone from an MP3 file using only iTunes.  I’ll be demoing on iTunes 9.0.0.70.  iTunes is needed to copy the ringtone to the phone, but we will also use to to create an AAC encoded audio file.

[more Click here to see my process]

I have no music in my iTunes (I don’t like iTunes, and don’t use it to manage my music library or my iPods).  This makes it easier to follow this tutorial.

Import your MP3 into the iTunes library.  From the “File” menu, select “Add File to Library…”, or press Ctrl+O.

Add File to Library

Browse to the source MP3 file.  This will add the file to the iTunes library.

MP3 in Library

Right-click the file and select “Get Info”

Get Info

In the resulting dialog, check the “Start Time” and “Stop Time” checkboxes.  Enter in the start and stop times in the MP3 that you want to use for your ring tone.  Ringtones are limited to 30 seconds (some sources say that you can do 40 seconds…I haven’t tried).

Mp3Ringtone4

With the item selected in the library, select the “Advanced” menu, and select “Create AAC Version”.  This will create a copy of the MP3 file, only using the region that was selected in the previous step.

In cases like mine, where my music library is not controlled by iTunes, the source MP3 file is in a different location from where the resultant AAC encoded file is saved.  My AAC is saved to %My Music%\iTunes\iTunes Media\Music\Disturbed\The Sickness.

The original file can now be removed from iTunes if you are not using iTunes to manage your MP3s.

Now, delete the newly created AAC encoded file from the iTunes library.  Make sure you answer “Keep File” when iTunes asks if you want to move the song to the recycle bin or keep it.

Remove from Library

Keep file

Now, rename the file extension from M4A to M4R.  Then import THAT file into iTunes.  Now it should show up as a ringtone.  New Ringtone

Ensure that iTunes is set up to sync ringtones, then, sync your iPhone.

Sync Ringtone

Now on your iPhone, go to Settings, Sounds, Ringtone, and select your newly upload ringtone.

Mp3Ringtone10 Mp3Ringtone11 Mp3Ringtone12

Now call yourself and enjoy.

Comment on this
Mike's Blog | Development

My iPhone and a new PC

Friday, 11 September 2009 01:56 PM
by Coose

Well, I just finished setting up my new PC, and I installed iTunes.  Everything smooth so far.  Remember, the happy unicorn iTunes does everything and you’ll never have to ever worry about anything.  That’s what the Mac guy on TV says.  Well, again, he’s wrong.

I didn’t have any podcasts, or music, or movies on my phone, so syncing those was no big deal.  I did, however, have pictures and applications installed.  When telling iTunes on the new PC to sync applications and sync pictures, it gave me the warning that everything would be erased from my iPhone.  Well, that’s not good.

I made a backup of my camera roll and let it sync the pictures.  Hey, cool…it didn’t erase all my pictures.  Oh wait…the other folders that were NOT in the camera roll are gone.  Damn…I didn’t back those up.  Can I restore an earlier backup?  Probably, but it’s not really worth it.

So what about my applications?  I don’t want to have to download everything again.  And what about the data that is on the phone…I sure don’t want to lose that.

Supposedly you can select the “Transfer purchases from XXX’s iPhone” from the File menu, and it will update the library with everything on the iPhone.  The problem with that strategy is that it doesn’t work.  After Googling for a while, I tried a trick to download a new free app from the app store using iTunes on the PC.  Then tried the transfer function again.  Well, we’re getting closer.  Now there are 4 pages of my apps in iTunes…but where’s the rest?  They are not all there.

If i ever get this figured out, I’ll post my solution here.

UPDATE:

Hilarious.  All my apps that start with the letter P-Z are not included in the “Transfer purchases…” functionality.  WTF Apple?

UPDATE:

Well, opening up my iTunes library mobile applications folder (C:\Users\Michael\Music\iTunes\iTunes Media\Mobile Applications), I could see that the apps starting with the letter P or greater were not there, so I kept that folder open, and kept hitting the “Transfer purchases…” option, watching them slowly start to appear.  Once I verified they were all there, I was able to select the “Sync Applications” checkbox in iTunes, and check all the applications, and was finally able to get a good sync.  I have no idea what caused that, or what fixed that.  But I sure don’t want to go through that again. :(

Comment on this
Mike's Blog | Development