Explosive Content

Lighting up your UI

Moved Blog

My blog has moved to http://geekswithblogs.net/tburger please visit me there.

  • Share/Bookmark

I finished my #TechEd 2010, may I have another??

It has been another fantastic year for TechEd North America.  I always love my time here.  First, I have to give a huge thank you to Ineta for giving me the opportunity to work the Ineta booth and BOF’s (birds of a feather).   I can not even begin to list how many fantastic leaders in the .Net space and Developers from all over I have met through Ineta at this event.  It has been truly amazing and great fun!!

New Orlean’s has been awesome.  The night life is hoppin’.  In addition to enjoying a few (too many??) of the local hurricanes in New Orleans, I have hung out with some of the coolest people  Deepesh Mohnani, David Poll, Viresh, Alan Stephens, Shawn Wildermuth, Greg Leonardo, Doug Seven, Chris Willams, David Carley and some of our southcentral hero’s Jeffery Palermo, Todd Anglin, Shawn Weisfeld, Randy Walker, The midnight DBA’s, Zeeshan Hirani, Dennis Bottjer just to name a few.

A big thanks to Microsoft and everyone that has helped to put TechEd together.  I have loved hanging out with people from the Silverlight and Expression Teams and have learned a ton.  I am ramped up and ready to take all that knowledge back to my co-workers and my community.

I can not wait to see you all again next year in Atlanta!!!

Here are video links to some of my fav sessions:

Using MVVM Design Pattern with VS 2010 XAML Designer – Rockford Lhotka

Effective RIA: Tips and Tricks for Building Effective Rich Internet Applications – Deepesh Mohani

Taking Microsoft Silverlight 4 Applications Beyond the Browser – David Poll

Jump into Silvelright! and become immediately effective – Tim Huckaby

Prototyping Rich Microsoft Silverlight 4 Applications with MS Expression Blend + SketchFlow – David Carley

Tales from the Trenches: Building a Real-World Microsoft Silvelright Line-of-Business Application – Dan Wahlin

  • Share/Bookmark

Mousin’ down the PathListBox

While modifying the standard media player with a new look and feel for Ineta Live I saw a unique opportunity to use their logo with a dotted I with and attached arc as the scrub control.

So I created a PathListBox that I wanted an object to follow when a user did a click and drag action.  Below is how I solved the problem.  Please let me know if you have improvements or know of a completely different way.  I am always eager to learn.

First, I created a path using the pen tool in Expression Blend (see the yellow line in image below).  Then I right clicked that path and chose [Path] –> [Make Layout Path].   That created a new PathListBox.  Then I chose the object I want to move down the new PathListBox and Placed it as a child in the Objects and Timeline window (see image below).  If the child object (the thing the user will click and drag) is XAML, it will move much smoother than images.

Just as another side note, I wanted there to be no highlight when the user selects the “ball” to drag and drop.  This is done by editing the ItemContainerStyle under Additional Templates on the PathListBox.  Post a question if you need help on this and I will expand my explanation.

Here is a pic of the object and the path I wanted it to follow.  I gave the path a yellow solid brush here so you could see it but when I lay this over another object, I will make the path transparent.

Image of Object and Path

 

To animate this object down the path, the trick is to animate the Start number for the LayoutPath.  Not the StartItemIndex, the Start above Span.

In order to enable animation when a user clicks and drags, I put in the following code snippets in the code behind. the DependencyProperties are not necessary for the Drag control.


namespace InetaPlayer
{
    public partial class PositionControl : UserControl
    {
        private bool _mouseDown;
        private double _maxPlayTime;
        public PositionControl()
        {
            // Required to initialize variables
            InitializeComponent();
            //mouse events for scrub control
            positionThumb.MouseLeftButtonDown += new MouseButtonEventHandler(ValueThumb_MouseLeftButtonDown);
            positionThumb.MouseLeftButtonUp += new MouseButtonEventHandler(ValueThumb_MouseLeftButtonUp);
            positionThumb.MouseMove += new MouseEventHandler(ValueThumb_MouseMove);
            positionThumb.LostMouseCapture += new MouseEventHandler(ValueThumb_LostMouseCapture);
        }
        // exposed for binding to real slider using a DependencyProperty enables animation, styling, binding, etc....
        public double MaxPlayTime
        {
            get { return (double)GetValue(MaxPlayTimeProperty); }
            set { SetValue(MaxPlayTimeProperty, value); }
        }
        public static readonly DependencyProperty MaxPlayTimeProperty =
            DependencyProperty.Register("MaxPlayTime", typeof(double), typeof(PositionControl), null); 
 
        // exposed for binding to real slider using a DependencyProperty enables animation, styling, binding, etc.... 
 
        public double CurrSliderValue
        {
            get { return (double)GetValue(CurrSliderValueProperty); }
            set { SetValue(CurrSliderValueProperty, value); }
        } 
 
        public static readonly DependencyProperty CurrSliderValueProperty =
            DependencyProperty.Register("CurrSliderValue", typeof(double), typeof(PositionControl), new PropertyMetadata(0.0, OnCurrSliderValuePropertyChanged)); 
 
        private static void OnCurrSliderValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PositionControl control = d as PositionControl;
            control.OnCurrSliderValueChanged((double)e.OldValue, (double)e.NewValue);
        } 
 
        private void OnCurrSliderValueChanged(double oldValue, double newValue)
        {
            _maxPlayTime = (double) GetValue(MaxPlayTimeProperty);
            if (!_mouseDown)
                if (_maxPlayTime!=0)
                    sliderPathListBox.LayoutPaths[0].Start = newValue / _maxPlayTime;
                else
                   sliderPathListBox.LayoutPaths[0].Start = 0;
        }
 
       //mouse control 
 
        void ValueThumb_MouseMove(object sender, MouseEventArgs e)
        {
            if (!_mouseDown) return;
            //get the offset of how far the drag has been 
            //direction is handled automatically (offset will be negative for left move and positive for right move)
            Point mouseOff = e.GetPosition(positionThumb);
            //Divide the offset by 1000 for a smooth transition
            sliderPathListBox.LayoutPaths[0].Start +=mouseOff.X/1000;
            _maxPlayTime = (double)GetValue(MaxPlayTimeProperty);
            SetValue(CurrSliderValueProperty ,sliderPathListBox.LayoutPaths[0].Start*_maxPlayTime);
        } 
 
        void ValueThumb_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            _mouseDown = false;
        }
        void ValueThumb_LostMouseCapture(object sender, MouseEventArgs e)
        {
            _mouseDown = false;
        }
        void ValueThumb_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _mouseDown = true;
            ((UIElement)positionThumb).CaptureMouse();
        } 
 
    }
}
 

I made this into a user control and exposed a couple of DependencyProperties in order to bind it to a standard Slider in the overall project.  This control is embedded into the standard Expression media player template and is used to replace the standard scrub bar.  When the player goes live, I will put a link here.

  • Share/Bookmark

Ineta Live is live but my player… close but not quite yet

The Ineta Live player is not quite done yet but I have been asked for the source from several people so here it is.

The feature changes I plan to work on on the way to TechEd

  • The scrub ball needs to be changed from an image to XAML for better look while click and drag.  this will allow me to connect it to the mouse speed. Note.. this really did work (not that I ever had a doubt :) ).  It is amazing how different the experience is between trying to use an image and when I got it changed over to a object in XAML.
  • The O’Data feed has some changes so I can calulate the percent – which broke what was there so it can be fixed it to be better
  • Finish the O’Data feed menu’s down to the list of videos
  • Catch up with any little details that need to be smoothed out

Since I am posting this early, as those things are done, I will cross them off the list and put a new version number below

Version 1.00  – 6/3/2010

Version 1.01 – 6/10/09 (wow how did a week slip by)

  • Share/Bookmark

O’Data Make me a Tag Cloud

image

** WATCH THIS POST FOR UPDATES**

In order to change the font and colors of the tags, I created 4 different styles in my Resource Dictionary (shown below).  I used a Mod function to choose which one to use but you can do what you want.

Resource Dictionary

    <Style x:Key="TagStyle0" TargetType="HyperlinkButton">
            <Setter Property="Foreground" Value="{StaticResource color_1_light}" />
            <Setter Property="FontFamily" Value="Verdana" />
            <Setter Property="Background" Value="{x:Null}"/>
    </Style>
    <Style x:Key="TagStyle1" TargetType="HyperlinkButton">
            <Setter Property="Foreground" Value="{StaticResource color_2_light}" />
            <Setter Property="FontFamily" Value="Courier New" />
            <Setter Property="Background" Value="{x:Null}"/>
    </Style>
    <Style x:Key="TagStyle2" TargetType="HyperlinkButton">
            <Setter Property="Foreground" Value="{StaticResource color_3_light}" />
            <Setter Property="FontFamily" Value="Georgia" />
            <Setter Property="Background" Value="{x:Null}"/>
    </Style>
    <Style x:Key="TagStyle3" TargetType="HyperlinkButton">
            <Setter Property="Foreground" Value="{StaticResource color_4_warm}" />
            <Setter Property="FontFamily" Value="Lucida Sans Unicode" />
            <Setter Property="Background" Value="{x:Null}"/>
    </Style>
The front setup is easy – the only important part is that you have a WrapPanel named CloudPanel.  This is where we will add the links.  
*TagCount is actually the percentage
Here is the code
 
   1:  namespace InetaPlayer
   2:  {
   3:      
   4:      public partial class InetaLiveTagCloud : UserControl
   5:      {
   6:          private DataServiceCollection<LiveTag> _LiveTags;
   7:          private INETALivePublic _context;
   8:   
   9:          public InetaLiveTagCloud()
  10:          {
  11:              InitializeComponent();
  12:              _context = new INETALivePublic(new Uri("[REMOVED]"));
  13:              _LiveTags = new DataServiceCollection<LiveTag>();
  14:              _LiveTags.LoadCompleted += LiveTags_Loaded;
  15:              var TagsQuery = (from p in _context.[REMOVED] orderby p.TagName ascending select p);
  16:              _LiveTags.LoadAsync(TagsQuery);
  17:          }
  18:   
  19:          private void LiveTags_Loaded(object sender, LoadCompletedEventArgs e)
  20:          {
  21:              if (_LiveTags.Continuation != null)
  22:              {
  23:                  _LiveTags.LoadNextPartialSetAsync();
  24:              }
  25:   
  26:              else
  27:              {                
  28:                  foreach (var liveTag in _LiveTags)
  29:                  {
  30:                      var linkTxt = new linkTxt{Text="|"+liveTag.TagName+"|", TextWrapping = TextWrapping.Wrap};
  31:                      var tagNum = (int)liveTag.TagCount%3;
  32:                      var linkBtn = new HyperlinkButton
  33:                      {
  34:                          Content=linkTxt,
  35:                          FontSize = (int)liveTag.TagCount +12,
  36:                          NavigateUri=new Uri("[REMOVED] "),
  37:                             HorizontalAlignment = HorizontalAlignment.Stretch,
  38:                            VerticalAlignment = VerticalAlignment.Stretch,
  39:                            HorizontalContentAlignment = HorizontalAlignment.Center,
  40:                            VerticalContentAlignment = VerticalAlignment.Center,
  41:                          Style = Application.Current.Resources["TagStyle"+tagNum.ToString()] as Style
  42:                      };
  43:                      
  44:                    CloudPanel.Children.Add(linkBtn);
  45:                  }
  46:              }
  47:          }
  48:      }
  49:  }

 
Initial Cloud ideas taken from http://silverlighttagcloud.codeplex.com/
  • Share/Bookmark

Recycle Reuse — put a new face on a standard template with Blend

Come join us at the Dallas XAML User group on 6/1/2010 where we will start with the standard MediaPlayer control and customize the style to fit my project.  We focus on some styling tips and tricks to make your content more flexible and orgainized.  In this presetentation expect to be exposed to template parts, styling resources, visual state manager, behaviors, and structure and functions of the MediaPlayer.  If you want to work with us, please bring a laptop with Expression Blend 4 installed (http://www.silverlight.net/getstarted/).  The standard MediaPlayer control is included with Expression Encoder.

  • Share/Bookmark

Look Ma, No VS 2010

Thank you, UT Dallas .NET User Group, for asking me to come talk about Blend.  I had a blast.  We went through a lot of the basics to get started with Blend but remember, that was just to get you started.  In no way was it comprehensive and a lot of those examples were derived just to show a capabiltiy.  Go forth and explore. 

Not bad for first presentation but there are things I will do better next time (already)
http://www.blip.tv/file/3646186
http://www.blip.tv/file/3647988

Here was the resource list for the meeting:
expression.microsoft.com
www.microsoft.com/design/toolbox
www.silverlight.net
victorgaudioso.wordpress.com
www.facingblend.com/blog
adamkinney.wordpress.com
channel9.msdn.com/shows/SilverlightTV

Here are some additional resorces for WP7:
http://electricbeach.org/?p=671
http://channel9.msdn.com/learn/courses/WP7TrainingKit/
http://chriskoenig.net/

Download Files

  • Share/Bookmark

Expanding Local File Access in a Silverlight 4 Out-Of-Browser Elevated Trust Application beyond the Special “My” Folders

For our needs, the announcement that Silverlight 4 would support local file system access was absolutely huge.  Of course, with this version, they have given an inch and I want at least a foot if not a yard!  Hopefully this is a first step that will lead to inclusion of further configurable file system access, perhaps in Silverlight 5.  Ideally there will be user selections, certainly controllable by Group Policy, that allow control of access to “My” folders, Home directory, removable devices, network shares accessible to the user, and everything on the machine that is accessible to the user.  In the interim, I have discovered a workaround.  Admittedly, it’s not pretty, but it does indeed work, at least for the external USB hard drive and thumb drive I tested it on.  Very interestingly, it also worked to enumerate files on a network share, but any attempt to access the files resulted in an Access Denied error.  I plan to look at that more closely since access to a network Home directory, or any other network share the user has access to is just as important as access to local storage.  This does may me wonder what happens if you are using roaming profiles and/or otherwise using folder redirection to store these “My” folders on the network.  Of course, I am pretty sure this could be addressed through a custom COM object, but it would be nice to be able to use this simpler hack instead of having to mess with building that.

Okay, enough fluff, what’s the trick?

Create an NTFS Symbolic Link within the desired “My” folder that links to the “other” media.

In my case, my external hard drive gets drive letter F: and everything I care about on that drive is in F:\Documents.  So, within C:\Users\Me\Documents, I create a link called RemovableDocuments that points there.  To do so, under in a Command Prompt running under Administrator, I execute

C:\Users\Me\Documents>MKLINK /D RemovableDocuments F:\Documents

After doing so, there will be a “special” shortcut-like link in C:\Users\Me\Documents.  Following it puts you directly in F:\Documents.

Once that is done, to fill a listbox with all of the JPEG files located in F:\Documents, I do the following:

in C#


{
    FileList.Items.Clear();
    foreach (string ThisFile in Directory.EnumerateFiles(string.Format("{0}\\{1}", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "RemovableDocuments"), "*.jpg")) {
        FileList.Items.Add(ThisFile);
    }
}

or in VB.Net

        FileList.Items.Clear()
        For Each ThisFile As String In Directory.EnumerateFiles(String.Format("{0}\{1}", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "RemovableDocuments"), "*.jpg")
            FileList.Items.Add(ThisFile)
        Next

To display the file that is currently selected in the FileList listbox, I do the following:

in C#

        private void FileList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.AddedItems.Count == 1)
            {
                try
                {
                    Filename = FileList.SelectedValue;
                    using (FileStream MyStream = File.Open(Filename, FileMode.Open))
                    {
                        BitmapImage bi = new BitmapImage();
                        bi.SetSource(MyStream);
                        Image1.Source = bi;
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

or in VB.Net

    Private Sub FileList_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) Handles FileList.SelectionChanged
        If e.AddedItems.Count = 1 Then
            Try
                Filename = FileList.SelectedValue
                Using MyStream As FileStream = File.Open(Filename, FileMode.Open)
                    Dim bi As BitmapImage = New BitmapImage
                    bi.SetSource(MyStream)
                    Image1.Source = bi
                End Using
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
        End If
    End Sub

I definitely hope this is only a temporarily needed workaround.  But, it’s better than nothing for my immediate needs.

  • Share/Bookmark

Visual Studio Tips and Tricks Giveaway

Zain has lost his mind.  He is giving away ThinkGeek gift certificates starting April 12th.  Read the rules here.  While you are there, pick up the Visual Studio Tip Extension .  I have it installed and have learned several new little “tricks” that help me be more effective (or to use as party tricks to wow my friends).

Update: I won!! Check it out, as of now (4/14/2010) the contest is still going on.

  • Share/Bookmark

Hosted Configuration for Silverlight 3 Business Application using WCF RIA Services (Beta) for Visual Studio 2008 / .Net 3.5 SP1

This article outlines issues encountered when deploying an application created from the Silverlight 3 Business Application template, using WCF RIA Services (Beta) for Visual Studio 2008 / .Net Framework 3.5 SP1.   The bulk of the solution was derived from this very helpful article by Rajneesh Noonia.

In the YourSilverlightSolution.Web project, set all of the RIA services References to Copy to Local.  This will probably include at least the following DLL’s:

  • System.ComponentModel.DataAnnotations.dll
  • System.Web.DomainServices.dll
  • System.Web.DomainServices.EntityFramework.dll
  • System.Web.Ria

After doing this, the application XAP file should load, but if the WCF services are not reachable, you will get an error similar to the following:

Load operation failed for query GetUser.  The remote server returned an error: NotFound

In the YourSilverlightSolution.Web project, add a Reference to System.ServiceModel,

In each service (AuthenticationService.vb or cs, UserRegistrationService.vb or cs and your domain service files)

In Visual Basic.Net, add:

Import System.SericeModel.Activation

In C#, add:

using System.ServiceModel.Activation;

Decorate each service with:

In Visual Basic.Net, add:

<AspNetCompatibilityRequirementsAttribute(RequirementsMode:=AspNetCompatibilityRequirementsMode.Required)> _

In C#, add:

[AspNetCompatibilityRequirementsAttribute(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

Add the following to web.config at the very bottom of the <runtime> section:

      <services>
      <service name="YourNamespace.Web.AuthenticationService" behaviorConfiguration="RIAServiceBehavior">
        <endpoint address="" binding="wsHttpBinding" contract="YourNamespace.Web.AuthenticationService" />
        <endpoint address="/soap" binding="basicHttpBinding" contract="YourNamespace.Web.AuthenticationService" />
        <endpoint address="/binary" binding="customBinding" bindingConfiguration="BinaryHttpBinding" contract="YourNamespace.Web.AuthenticationService" />
      </service>

      <service name="YourNamespace.Web.UserRegistrationService" behaviorConfiguration="RIAServiceBehavior">
        <endpoint address="" binding="wsHttpBinding" contract="YourNamespace.Web.UserRegistrationService" />
        <endpoint address="/soap" binding="basicHttpBinding" contract="YourNamespace.Web.UserRegistrationService" />
        <endpoint address="/binary" binding="customBinding" bindingConfiguration="BinaryHttpBinding" contract="YourNamespace.Web.UserRegistrationService" />
      </service>

      <service name="YourNamespace.Web.YourDomainService" behaviorConfiguration="RIAServiceBehavior">
        <endpoint address="" binding="wsHttpBinding" contract="YourNamespace.Web.YourDomainService" />
        <endpoint address="/soap" binding="basicHttpBinding" contract="YourNamespace.Web.YourDomainService" />
        <endpoint address="/binary" binding="customBinding" bindingConfiguration="BinaryHttpBinding" contract="YourNamespace.Web.YourDomainService" />
      </service>

      </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="RIAServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <bindings>
      <customBinding>
        <binding name="BinaryHttpBinding">
          <binaryMessageEncoding />
          <httpTransport />
        </binding>
      </customBinding>
    </bindings>

Replace the <system.serviceModel> section with (or update the bolded line as necessary):

  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true">
      <baseAddressPrefixFilters>
        <add prefix="http://yourdomain.com/"/>
      </baseAddressPrefixFilters>
    </serviceHostingEnvironment>
  </system.serviceModel>

The prefix entry above MUST match the host header that is set for the web site.

  • Share/Bookmark