Silverlight Custom Cursor Re-visited

by Bobbi Perreault 13. July 2011 21:28
Share on Facebook

In Silverlight 4.0 application I needed to have a line follow the mouse for comparing between line charts.  I Googled Silverlight 4.0 custom cursor and number three on the results was my old-old blog post about a custom cursor I put into a drawing program.  That took me back a ways.  ha ha.

For this app, my needs are simple, heck, I don't even need to hide the cursor.  I just want a line to follow the cursor while the mouse is over a specific panel.  So here's how I did it.

  1. I added a Path object to the XAML of my page.  This Path needs to be on top, so it's at the bottom of the XAML just before the closing </Grid>.  Visibility is turned off so it doean't intrude until needed.
    <Path Data="M122,198 L122,583.57233" Fill="#FF01010C" x:Name="cursorline"
    Visibility="Collapsed" HorizontalAlignment="Left" Grid.Row="1"
    Stretch="Fill" Stroke="Black" UseLayoutRounding="False"
    Width="1"/>
  2. I added mouse move event handlers to the containing grid, called imaginatively LayoutRoot.
    <Grid x:Name="LayoutRoot" MouseEnter="LayoutRoot_MouseEnter" 
    MouseLeave="LayoutRoot_MouseLeave"
    MouseMove="LayoutRoot_MouseMove">
  3. In Mouse Enter event handler, I set the visibility of my path to Visible.
  4. In Mouse Leave event handler, I set the visibility of my path to Collapsed.
  5. In Mouse Move event handler, I set the margin of my path to line up with the horizontal position of my cursor.  Here's the code.
            private void LayoutRoot_MouseEnter(object sender, MouseEventArgs e)
    {
    cursorline.Visibility = System.Windows.Visibility.Visible;
    }
    private void LayoutRoot_MouseLeave(object sender, MouseEventArgs e)
    {
    cursorline.Visibility = System.Windows.Visibility.Collapsed;
    }
    private void LayoutRoot_MouseMove(object sender, MouseEventArgs e)
    {
    cursorline.Margin = new Thickness( e.GetPosition(LayoutRoot).X, 0, 0, 0);

Ok then. Have a great day.

Tags:

How To

Silverlight to Sharepoint – Upload Image

by Bobbi Perreault 2. April 2010 05:27
Share on Facebook

 

Upload images to Sharepoint using Silverlight and SPAPI (a link to the code in a txt file for easier copying-silverlightImageUpload.txt (5.53 kb) )

 

This little piece of code is a Silverlight control that will place an image into a Sharepoint folder. After the upload, a thumbnail of that image is placed into the UI for feedback to the user. It uses the opensource Javascript to Sharepoint library, SPAPI, http://darrenjohnstone.net/2008/07/22/ a-cros....

In the Html that holds your Silverlight object definition, include the two SPAPI files Core and Imaging. The function sendImageToSharepoint will be used by your Silverlight object after it has been told what image to send to Sharepoint. I keep mine in another javascript file and it's also part of a larger object, I've placed just the piece used to upload here because the rest of that object doesn't apply here.

html------------------------------------------------

  <script src="scripts/SPAPI_Core.js" type="text/javascript"></script>
    <script src="scripts/SPAPI_Imaging.js" type="text/javascript"></script>
<script type="text/javascript">
    sendImageToSharepoint: function(strListName, strFolder, bytes, fileName) {
        var lists = new SPAPI_Imaging(labstools.sharepointUrl);
        var returned = lists.upload(strListName, strFolder, bytes, fileName, true);
        if (returned.status != 200) {

            alert("There was an error: " + returned.statusText);

        };

    }
</script>

In the Silverlight UserControl XAML file, place this StackPanel, it will be your user's point of interaction with the control. The second StackPanel, imagestorage, is used to place the thumbnail image.

Xaml--------------------------------------------------

<StackPanel Orientation="Horizontal" Margin="0,5,0,0">
    <TextBlock Text="Attach Images(s):" TextWrapping="Wrap" Width="100"/>
    <TextBox x:Name="ImageFile" TextWrapping="Wrap" Width="211"/>
    <Button x:Name="btnUploadImage" Width="75" OnClick="bOpenFileDialog" Content="Browse" Style="{StaticResource styleA}" Height="25" Margin="5,0,0,0"/>
</StackPanel>
<StackPanel x:Name=" imagestorage" />

In the Silverlight UserControl XAML code behind file, place this code, it is the Click event handler for btnUploadimage.. The Javascript function that is used to communicate with SPAPI is in a Namespace called labsSurveyQues, so you can see that being initialized in this code as well. One piece that isn't shown here, is where the EventHandler was added for CompositionTarget_Rendering, this piece of code syncronizes with the UI to place the thumbnail. I got this from Jeff Prosise's Blog, http://www.wintellect.com/CS/blogs/jprosise/archive/2008/10/24/cool-silverlight-trick-5.aspx

behind Xaml:------------------------------------------------

 Private Sub bOpenFileDialog(sender as Object, evt as EventArgs)
        ' Create an instance of the open file dialog box.
        Dim openFileDialog1 As OpenFileDialog = New OpenFileDialog
        Dim so As ScriptObject = TryCast(HtmlPage.Window.Eval(&quot;labsSurveyQues&quot;), ScriptObject)

        ' Set filter options and filter index.
        openFileDialog1.Filter = &quot;Image Files (*.png, *.jpg, *.jpeg)|*.png;*.jpg;*.jpeg&quot;
        openFileDialog1.FilterIndex = 1

        openFileDialog1.Multiselect = True

        ' Call the ShowDialog method to show the dialogbox.
        Dim UserClickedOK As Boolean = openFileDialog1.ShowDialog

            ' Process input if the user clicked OK.
        If (UserClickedOK = True) Then
           
            _files.Clear()
            For Each file1 As FileInfo In openFileDialog1.Files

                    Dim tb As New TextBlock
                    tb.Text = openFileDialog1.File.Name
                    tb.Name = &quot;image_&quot; + imagestorage.Children.Count.ToString()

                    Dim testextension As String = tb.Text.ToLower()
                    If testextension.Contains(&quot;jpg&quot;) Or testextension.Contains(&quot;jpeg&quot;) Or testextension.Contains(&quot;png&quot;) Then
                        imagestorage.Children.Add(tb)

                    '' ''Open the selected file to read.
                    Dim fileStream As System.IO.Stream = openFileDialog1.File.OpenRead
                    Dim binary As BinaryReader = New BinaryReader(fileStream)
                    Dim imgB() As Byte = binary.ReadBytes(fileStream.Length)
                    fileStream.Close()

                    'send the binary stream to the script that will put it out to the server for me
                    so.Invoke(&quot;sendImageToSharepoint&quot;, &quot;PictureLibrary&quot;, &quot;&quot;, Convert.ToBase64String(imgB), file1.Name)

                    _files.Enqueue(file1) 'displays to the UI

                End If
            Next
        End If
    End Sub

    Private _files As New Queue(Of FileInfo)()
       Private Sub CompositionTarget_Rendering(ByVal sender As [Object], ByVal e As EventArgs)
        Dim imagestorage As StackPanel = DirectCast(FindControls.RecursiveFindControl(controlspanel.Children, &quot;imagestorage&quot;), StackPanel)
        If _files.Count &lt;&gt; 0 And imagestorage IsNot Nothing Then
            Dim fi As FileInfo = _files.Dequeue()
            Using stream As Stream = fi.OpenRead()
                Dim bi As New BitmapImage()
                bi.SetSource(stream)
                Dim Img As New Image
                Img.Source = bi
                imagestorage.Children.Add(Img)
            End Using
        End If
    End Sub

 

Identify the Active Directory Username from Silverlight app from Sharepoint

by Bobbi Perreault 25. November 2009 01:10
Share on Facebook

I needed to know the Active Directory username of the current user from my Silverlight app.  The Silverlight control is running from a Sharepoint site. 

It seems that this isn't as easy as you would think.  I found several ways, but the one I ended up using wasn't one of them.

  1. Page.User.Identity.Name.Split('\\')[1];  - this would work from code behind or even in alligator tags in front end - but my Sharepoint page wouldn't allow them.
  2. var wshshell=new ActiveXObject("wscript.shell");
    var username=wshshell.ExpandEnvironmentStrings("%usern ame%");

For i As Integer = 0 To Request.ServerVariables.Count - 1
Response.Write(Request.ServerVariables.Keys(i) & " : <br /> [ " & Request.ServerVariables(i) & " ] <br /> ")
Next

This one is totally hard to do under any type of security scenario.

  1. HttpContext.Current.Profile.UserName  - again, this would work from code behind or even in alligator tags in front end - but my Sharepoint page wouldn't allow them.
  2. <script type="text/vbscript" language="VBscript">
    Dim X
    set X = createobject("WSCRIPT.Network")
    dim U
    U=x.UserName
    'MsgBox "username: " & U
    </script>
    <script type="text/javascript" language="Javascript">
        var a = U;
        $("#name").text(a.toString());
    </script>

Hard to even print these two that use active x!  But for the sake of completeness, here they are.

AND - The way I used:

When my Silverlight app is loaded, the first thing I do is send a web service request to add a list item to a log list.  The list has only one field, that is Title.  So I add an "application opened" record to the log.   What I get in return is an xml confirmation that the record was added - the confirmation contains the name of the logged in user - which is their active directory name.  I just parse the correct element out "ows_Author" using XLinq and have what I needed.

Is this weird?  Cause I wouldn't be surprised!  Anyway, it works for me.

Tags:

How To

Silverlight Elastic List Control

by Bobbi Perreault 30. May 2009 11:59
Share on Facebook

For this contest entry, How People Use Global’s Millennium, I chose to present the data using the Elastic List concept described here.  This is a post on how I built a piece of the Elastic List control, that is the controlling ListBox.

I was asked to share the source, Sure, no problem.  If you'd like the whole package, it's right here.

Elastic List ListBox

The ListBox that controls this chart needs to do three things:  1. Display the items in descending order of occurrance.  2. Color the items in respect to their occurrance and 3. Size the items in respect to their occurrance.

The Phizzpop contest entry provided a DataVisualization project which was to serve as the starting point.  In this project was the datasource, Customersurveys.xml.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<CustomerSurveys xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <Survey>
  <CustomerId>1</CustomerId>
  <Device>DX100 MP3 Player</Device>
  <Month>9</Month>
  <Year>2008</Year>
  <TimeUsed>20</TimeUsed>
  <Activity>Driving</Activity>
 </Survey>

The Xaml for the ListBox:

 

<PP4:ListControl x:Name="ActivityList" Title="Activities" Width="200" Height="343" VerticalAlignment="Top" AllClicked="ActivityList_AllClicked" FilterClicked="ActivityList_FilterClicked" SelectionChanged="ActivityList_SelectionChanged" LockClicked="ActivityList_LockClicked" Margin="0,0,5,0"/>

 

 

Loading a list from the xml file:

XmlReader reader = XmlReader.Create(s); XElement elementRoot = XElement.Load(reader); IEnumerable<DataItemXml> theBarItems = from element in elementRoot.Descendants("Survey") select new DataItemXml {  CustomerId = (int)element.Element("CustomerId"),  Device = (string)element.Element("Device"),  Month = (short)element.Element("Month"),  Year = (short)element.Element("Year"),  TimeUsed = (short)element.Element("TimeUsed"),  Activity = (string)element.Element("Activity") }; _barItems = theBarItems.ToList<DataItemXml>();

 

Use the list _barItems, to load our declared ListBox, ActivityList using this structure:

public class DataItem
 {
  public int Index { get; set; }
  public string Description { get; set; }
  public double Value { get; set; }
  public double Percentage { get; set; }
  public double ItemHeight { get; set; }
  public SolidColorBrush ItemColor { get; set; }
 }

.

 private List<DataItem> getWeightedActivityList()
{
 List<DataItemXml> activities = _barItems.GroupBy(b => b.Activity).Select(g => g.First()).ToList();
 // compute the percentage size of each activity
 List<DataItem> dataItems = new List<DataItem>();
 foreach (DataItemXml activity in activities)
 {
  DataItem dataItem = new DataItem();
  dataItem.Index = activities.IndexOf(activity);
  dataItem.Description = activity.Activity;
  double total = _barItems.Sum(b => b.TimeUsed);
  double thisTotal = _barItems.Where(b => b.Activity == activity.Activity).Sum(b => b.TimeUsed);
  dataItem.Percentage = thisTotal / total;
  dataItem.Value = thisTotal;
  
  double itemheight = 15 + (dataItem.Percentage * 100);
  dataItem.ItemHeight = itemheight;
  dataItem.ItemColor = getColorFromPercentage(dataItem.Percentage);
  dataItems.Add(dataItem);
 }
 dataItems.Sort(delegate(DataItem d1, DataItem d2) { return d2.Percentage.CompareTo(d1.Percentage); });
 return dataItems;
}

In the ListBox control, here is how we bind our ListItems so that they will use the items we initialized for Sizing and Coloring:

 <ListBox x:Name="ItemsList"  Margin="0,5,0,0" 
  Style="{StaticResource BlueListBoxStyle}" 
  SelectionChanged="ItemsList_SelectionChanged" Width="190" Height="270" >
<ListBox.ItemTemplate>
 <DataTemplate>
  <StackPanel Margin="0,0,0,0" Background="{Binding ItemColor}" Orientation="Horizontal" Height="{Binding ItemHeight}">
<TextBlock Text="{Binding Description}" x:Name="Body" Style="{StaticResource listcolumn}" Width="100"  />
<TextBlock Text="{Binding Value}" x:Name="Weight" Style="{StaticResource listcolumn}" Width="50"  />
  </StackPanel>
 </DataTemplate>
</ListBox.ItemTemplate>
 </ListBox>

Convert Bitmapped Waves to Silverlight Animated Waves

by Bobbi Perreault 1. February 2009 04:05
Share on Facebook

Hope in Perilous TimesI wanted to see how a person could take a bitmap (the bitmap is of a fake lake I created from a mountain picture. ) and animate it. In order to animate the waves of my lake, I had to create vector based paths that would echo the shapes of the waves. So - this is just a post about how I fumbled around to get my bitmap waves converted into vector waves - and here's the result: Water effect using animated paths in Silverlight I Hope you have your browser window big, because the image is 1024 X 800.

 

Here are the steps I took all in their raw fumbling glory.

Paint.NET layered working surface

In Paint.NET, You can download the original PDN file here

  • I hid all the layers except Layer #4 which is the darkened transparent overlay that was sliced up for waves.
  • I saved that image - 'justdarkenedwaves.png'
  • Whoops, have to switch to PhotoShop.....Import the file, justdarkenedwaves.png into photoshop and save it as a .psd file. for the step after next.
  • I opened the finalized .jpg I created as the last step of my previous post in Illustrator, that's the file I called 'flatironswithlake.jpg'
  • I placed the .psd file I created above into layer #2 inside of Illustrator. It needed to be squished down to into the water area, it wasn't the same proportion as the .jpg in layer 1.
  • I selected Illustrator's auto trace tool, and started clicking on the 'waves' until they were all traced. How to find the autotrace tool
  • I selected just the new paths, and cut them out of the picture (keeping them on my clipboard)
  • I deleted the waves (bitmap) that I just traced.!
  • I pasted the paths of the traced waves back into a layer by themselves and positioned these vector images over the water in the layer below.

 

I was able to take this over into Expression Design now by simply selecting all and copying them, then pasting into a new document in Design. This is the intermediate step in getting the paths into Blend. So the last piece is to Select all in Expression Design and Copy Xaml. Then take my clipboard full of Xaml over to a new Silverlight project in Blend and paste them in.

Animating the waves was done in two stages. My Paths I just imported were 165 count all in a group called Layer1. In stage one, I created a new animation for pieces of the paths, picking and choosing which ones. Each animation was maximized for effect, and all I did was change the opacity a bit. Move it back and forth gently a few pixels here and there.

the second animation was done on a copy of Layer1, which took all 165 paths in a bunch and made another group. This group I stretched out to be twice as wide as my image. Over the course of 60 seconds, I drag that across the screen. This gives the effect of gently flowing water. Opacity is kept under 50.

I learned a lot. Next time (today) I'm making a windmill prototype, I'll put it up if I manage to get done!

 

Tags:

How To

Use Paint.NET to Create a Lake

by Bobbi Perreault 16. January 2009 20:05
Share on Facebook

Paint.NET is free software for digital photo editing.  I use it for 85% of my bitmap image processing needs - about the only time I switch to Photoshop is when I need to remove backgrounds because the Polygonal lasso tool makes it so easy. 

I had some fun this morning by putting a lake where none existed.  I started with a picture of FlatIrons that was taken by me when I worked in Longmont. 

I first increased the size of my canvas by adding 120 or so pixels onto the bottom. (Ctrl-R, or Image-Resize)

I used the Rectangle Select tool to select the mountain piece, then Ctrl-C to copy it.  Ctrl-Shift-V pastes my selection into a new layer.

From the Layers menu, select "Flip Vertical" and this will turn it upside down.  Then I type 'M' to get the 'Move Selected Pixels' tool, and move the flipped layer down to the bottom of my canvas.  This lines up the old bottom of the picture with a flipped copy of it's self.

 

 

Keep this layer selected. 

Use the Effects-Noise-Add Noise menu item to litter up the selection with a bunch of white specs.

Use the Effects-Blur-Motion Blur menu item to make the water 'wavy' - Do that by setting the angle to 180 and extending the blur to lengthen the lines.  Keep this selection active.

Once again, copy then paste into a new layer. 

Set the layer properties to Transparency of 70.  (F4 to access, or Layers-Properties)

Keeping this area selected, bump up the contrast to lighten this layer.

 

Move your layer selection back down to the first layer, the original picture - but keep your 'water' selection active.  Copy once again.

Move your layer selection up to the layer that is lightened and made transparent.  Then once again, paste your clipboard into a new layer.

For this third layer - once again set the transparency to 90.  This time use the Contrast tool (Ctrl-Shift-C, or Adjustments-Brightness/Contrast) to Darken the layer.

Now here's the fun piece.  Grab the Lasso select tool and with your mouse down for the whole time - drag your cursor back and forth and back and forth in a wave pattern across the darkened layer you just added.  Keep the lines you're drawing very skinny at the top of your "water" and far apart.  By the time you get to the bottom of your "water" your polygons should be wider - but closer to each other - think wave.

When you've filled the water with your lines, let up the mouse this will select portions of the transparent darker layer.  DELETE your selection.  And magic waves appear.

Here's a link to the final product - I like it for the background of my Twitter page.

NEXT - I'm going to take my waves into Expression Design.  These guys are going to ripple across the screen in the background of my new toy web site, Dont Call Me Late For Supper.

 

 

RSS Feed FriendFeed