in

vbCity Blogs

New (temp) place for vbCity Blogs

CanOz Blog

Neil Knobbe's place for Visual Basic.NET and WPF

July 2009 - Posts

  • Extra ScrollBars with Silverlight 3

    This was a rather interesting one that I only stumbled upon.

    Now that Silverlight 3 has been released, I figured it was time to update some web sites that I look after and get away from the plain HTML with CSS that I had been using.

    It took much less time that I thought to get the first site set out and running the way I wanted or so I thought.

    Most of the site content was put into a ScrollViewer as I knew it would extend past the bottom of the window and someone viewing the site would be required to scroll at some point in time.

    I developed the site on my laptop and it all through development and deployment it looked fine, but when I happened to take a look at the site on my desktop machine I noticed that there were two ScrollBars showing on the Internet Explorer window.

    This was a mystery to me as I knew that there were not two ScrollBars when I was developing the site.

    After a giving this problem some serious though for a while I realized what the problem may be.  Normally I keep both machines the same but currently my laptop and desktop were different in one aspect.

    Internet Explorer.

    My laptop was running Vista with Internet Explorer 7 and my desktop was running Vista with Internet Explorer 8.  At least now I knew where the problem lay.  Not how to fix the problem mind you, just why I was seeing what I was.

    As it turns out the fix is quite simple.

    When Visual Studio creates a Silverlight application, and the accompanying web site that can host the Silverlight application, it adds some CSS Style for the page.

    <head>

        <title>SilverlightApplication4</title>

     

        <style type="text/css">

        html, body {

            height: 100%;

            overflow: auto;

        }

        body {

            padding: 0;

            margin: 0;

        }

        #silverlightControlHost {

            height: 100%;

        }

        </style>

     In the HTML above it is the value of the overflow property that determines if the ScrollBar for the window is displayed or not.

    IE8 is just different enough from IE7 that setting the overflow to auto generates the extra ScrollBar.  I suppose a better way to say it is that it does not let the ScrollBar from the Silverlight application replace the ScrollBar of the IE window like it does in previous versions.

    To get around this problem, you need to change the overflow setting from “auto” to “hidden”.

    <head>

        <title>SilverlightApplication4</title>

     

        <style type="text/css">

        html, body {

            height: 100%;

            overflow: hidden;

        }

        body {

            padding: 0;

            margin: 0;

        }

        #silverlightControlHost {

            height: 100%;

        }

        </style>

     Once overflow is set to hidden, IE will open without a ScrollBar which leaves the person viewing the site with the ScrollBar of the Silverlight application to use instead.

    These are the kinds of problems that I like.  Nice and easy to fix.

  • Blending Images

    Recently I have been updating, or rather upgrading may be a better word, a few web sites that I have been looking after for years.

    I have been using some Javascript to blend images in a sort of slide show and decided that if I was going to change the web sites over to Silverlight 3.0 that it was as good as time as any to replace the decade old Javascript as well.

    I would like to say that I am so well versed in XAML that all I had to do was manually type in the required XAML to the Silverlight project that I started in Visual Studio, but alas such is not the case so I had to use the very handy Expression Blend as the tool to create the effect I wanted for the images.

    The effect I was after was to have a set of five images that would be displayed one at a time then after a set time dissolve to display the next image in an endless loop.

    To accomplish this I knew that I would need to create a Storyboard and use DoubleAnnimationUsingKeyFrames to get the job done.

    I placed all five images in one cell of a Grid,

    setting the Height property of all the images to be the same as well as setting the Opacity of four of the images to 0 and the Opacity of the last to 1 so that only one image was visible at the start.
    So my starting XAML is:

    <Window

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        x:Class="Window1"

        x:Name="Window"

        Title="Window1"

        Width="640" Height="480">

     

        <Grid x:Name="LayoutRoot">

            <Image Name="image1" Source="pics\jps6.jpg" Height="200" Opacity="1"/>

            <Image Name="image2" Source="pics\jps9.jpg" Height="200" Opacity="0"/>

            <Image Name="image3" Source="pics\jps11.jpg" Height="200" Opacity="0"/>

            <Image Name="image4" Source="pics\kids.jpg" Height="200" Opacity="0"/>

            <Image Name="image5" Source="pics\play7.jpg" Height="200" Opacity="0"/>

        </Grid>

    </Window>

     

    The next step was to create the Storyboard.  To create a Storyboard you need to click the New button located on the Objects and Timelines panel.

    After clicking the New button you are prompted to either accept the default name for the Storyboard or enter your own name for the Storyboard.  For my example I have renamed the Storyboard “BlendingImages”.

    Once you have accepted the name for the Storyboard, Timeline recording is turned on and a Storyline is added to the Objects and Timeline panel.

    Next a KeyFrame for the Element to be changed, in my case the first image, needs to be added.  To add a KeyFrame you need to do two things.

    1)  In the Objects and Timeline panel select the Element you want to add the KeyFrame for. (Number 1 in the image below.)

    2)  Click on the Record KeyFrame Button above the Timeline. (Number 2 in the image below.)

    A KeyFrame will then be added to the Timeline of the Element that has been selected. (Number 3 in the image below.)

    Now that the KeyFrame has been added the Properties for the Element can be changed to what I want in the Properties Panel of the Element.  In my case I don’t actually want to make any changes to the Element just yet.

    The effect that I am going for is to have the image show for six seconds then fade away over the next three seconds.  When the image that is showing starts to fade, I want the next image to start to appear over the same three seconds that the current image is fading.

    Adding a second KeyFrame is the same as adding the first one.  Move the Timeline but using the small ScrollBar under the actual Timeline until the six second line is visible then click the Record KeyFrame button again.  A second KeyFrame for the Element will be inserted on the timeline for the Element.

    The second image is selected and a KeyFrame is added to the Timeline for the second image.

    Once again I don’t want to make any changes to the Properties of either image, but if you wanted to all you need to do is select the Element and then set whatever Properties you want in the Properties panel for the Element.

    Another KeyFrame needs to be added for each image at nine seconds.

    Now I am ready to make some changes to the Properties of my two images.

    For the first image I set the Opacity to 0 which will make it invisible and the second image I set the Opacity to 100 so that is will now be seen.

    You will also notice that it shows in the Objects and Timeline panel that there has been changes to the Elements.

    One other point you may be curious about is why I added the KeyFrame to image1 at six seconds.  The reason for this is the change in an Elements Property is done over the entire time between KeyFrames.  As a result the image would be wholly visible for about half the time, four and a half seconds, before starting to fade prior to the second image started to appear which is not the effect I was after.  By adding the second KeyFrame at six seconds I ensured that the first image was still wholly visible at the time the second image started to fade in.

    You can click on the Play button in the Objects and Timeline panel to test the Effect to make sure that it is working the way you want.

    The starting animation worked so I set about adding KeyFrames and setting Properties for the rest of my images to complete the blending effect.

    I should mentions that since I wanted this effect to repeat, the last three second of the effect I set the original image to start to become visible again and the last image fade out.

    To get the effect to repeat you need to set the RepeatBehaviour property of the Storyboard.  You can do this by either adding the XAML yourself or by clicking once on the name of the Storyboard in the Objects and Timelines panel then selecting the value for the RepeatBehaviour.

    I wanted to effect to continually repeat so I set the property to Forever.

    Testing the effect showed it worked so I was able to now insert the XAML for the Storyboard into the Silverlight project in Visual Studio.

    Below is the complete XAML for the Storyboard.

            <Storyboard x:Key="BlendingImages" RepeatBehavior="Forever">

                <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"

                                              Storyboard.TargetName="image1"

                                              Storyboard.TargetProperty="(UIElement.Opacity)">

                    <SplineDoubleKeyFrame KeyTime="00:00:06" Value="1"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:09" Value="0"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:42" Value="0"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:45" Value="1"/>

                </DoubleAnimationUsingKeyFrames>

                <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"

                                              Storyboard.TargetName="image2"

                                              Storyboard.TargetProperty="(UIElement.Opacity)">

                    <SplineDoubleKeyFrame KeyTime="00:00:06" Value="0"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:09" Value="0.995"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:15" Value="0.995"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:18" Value="0"/>

                </DoubleAnimationUsingKeyFrames>

                <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"

                                              Storyboard.TargetName="image3"

                                              Storyboard.TargetProperty="(UIElement.Opacity)">

                    <SplineDoubleKeyFrame KeyTime="00:00:15" Value="0"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:18" Value="0.995"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:24" Value="0.995"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:27" Value="0"/>

                </DoubleAnimationUsingKeyFrames>

                <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"

                                              Storyboard.TargetName="image4"

                                              Storyboard.TargetProperty="(UIElement.Opacity)">

                    <SplineDoubleKeyFrame KeyTime="00:00:24" Value="0"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:27" Value="1"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:33" Value="1"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:36" Value="0"/>

                </DoubleAnimationUsingKeyFrames>

                <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"

                                              Storyboard.TargetName="image5"

                                              Storyboard.TargetProperty="(UIElement.Opacity)">

                    <SplineDoubleKeyFrame KeyTime="00:00:33" Value="0"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:36" Value="1"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:42" Value="1"/>

                    <SplineDoubleKeyFrame KeyTime="00:00:45" Value="0"/>

                </DoubleAnimationUsingKeyFrames>

            </Storyboard>

     To get the effect running there was a couple of tweaks that were required in the Silverlight project.

    The first was I needed to give the UserControl a Name so that I could access the Events for the UserControl from the .vb code behind page.

    Opening the code behind page I went to the Loaded Event of the UserControl and added the code that would find the Storyboard as a Resource of the UserControl and start the effect when the page was loaded into the user browser.

    The code is relatively simple at three lines.

    The first line declares a Variable as a Storyboard.

    The second line sets the value of the Variable to be the Storyboard that I created in Blend and copied into my Silverlight project.

    The third line of code starts the Storyboard to begin the effect.

        Private Sub BlendingImages_Loaded(ByVal sender As Object, _

                                      ByVal e As System.Windows.RoutedEventArgs) _

                                      Handles BlendingImages.Loaded

     

            Dim MyStory As Storyboard

     

            MyStory = CType(Me.Resources("BlendingImages"), Storyboard)

     

            MyStory.Begin()

     

        End Sub

     Now I have the same effect, which can be seen here as I had before with a couple of benefits.

    The first benefit is that I am not limited to needing all the images to be exactly the same size and shape and the markup for the XAML Storyboard is less than the Javascript function.

  • WPF Pages and Custom Designed Hyperlinks

     It seems like Hyperlinks are my main focus this week.

    Once I had gotten the Hyperlinks with Images working for my current project, I got to thinking about my next project and just what I could get Hyperlinks to look like.  It turns out that you could do just about anything you want to create a Hyperlink.  The only thing limiting you is your imagination though you may want to temper your imagination and not make anything too gaudy.

    I had a vague idea of what I wanted and one thing I definitely wanted to do was use the existing colour scheme using Yellow and Teal.  Instead of two separate colours I decided I wanted to use a Gradient colour so the first thing I did was create a LinearGradientBrush as a Page Resource so I could easily re-use it throughout the project.

        <Page.Resources>

            <LinearGradientBrush x:Key="MyBrush"

                                StartPoint="0,0" EndPoint="1,1" Opacity=".75">

                <GradientStop Color="Yellow" Offset="0"></GradientStop>

                <GradientStop Color="Teal" Offset="1"></GradientStop>

            </LinearGradientBrush>

        </Page.Resources>

     I am going to make a small side trip here, but I feel it is an important one.  In this post, and my two previous, I mention that I am using a Windows Presentation Foundation (WPF) Page for my projects.  I also mentioned that the Users web browser, Internet Explorer 6 in this case, is going to be used to view the page.  (At the time of writing this post you can only use Internet Explorer 6 or higher to view a page with XMAL markup).

    Without a slight modification to a Page that is automatically generated by Visual Studio, and Expression Blend, the page itself will not open in the web browser.  There will be an error generated.

    When Visual Studio creates a WPF Page the XAML markup for the page looks like the following:

    <Page x:Class="Page1"

       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

       Title="Page1">

        <Grid>

     

        </Grid>

    </Page>

     which is fine if you are going to run your application in a WPF Navigation window.  If you, like I want, wish to display the page directly in Internet Explorer, then you must remove the reference to the Class name.  Your XAML for the base page would now look like:

    <Page

       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

       Title="Page1">

        <Grid>

     

        </Grid>

    </Page>

    Now if you were to add some content to your page and try to open it with Internet Explorer the page would display assuming there are no errors in the page content XAML.

    With that small explanation out of the way it is back to the project.

    I wanted to have my Hyperlinks as an irregular shape, but not so irregular that I needed to create a Polygon shape for them.  What I was thinking of was something rectangular but with not all the corners squared.   The easiest way that I use for this is to use a Border.

    Knowing that I can’t use a Hyperlink without it being in an UIElement, I put a Hyperlink in a TextBlock and added the Border XAML between the opening and closing tags of the Hyperlink.

    I applied the LinearGradientColor I added as a page resource as the colour, or Brush, for the Border and set the Thickness of the Border to 10.  To give the Border a look of something other than a rectangle, I changed the top left and bottom right CornerRadius to 20 and 10 respectively.

            <TextBlock>

            <Hyperlink>

                <Border BorderBrush="{StaticResource MyBrush}"

                       BorderThickness="10" CornerRadius="20,0,10,0">

                </Border>

            </Hyperlink>

            </TextBlock>

    This gave me a starting point as can be seen in the following screenshot.

    Yes the Border is very small, but that is only because I have not put any content into it yet.  There is also that annoying little blue line showing it to be a Hyperlink too which I will deal with later.

    The Border can only hold one WPF Element, which will suit my purposes fine, but if you want to be more elaborate you will need to add a container such as the Grid before adding any other Elements.

    I am using a TextBlock to display the Caption of the link so between the opening and closing tags of the Border I inserted the XAML for the TextBlock.

            <TextBlock>

            <Hyperlink>

                <Border BorderBrush="{StaticResource MyBrush}"

                       BorderThickness="10" CornerRadius="20,0,10,0">

                    <TextBlock Background="{StaticResource MyBrush}"

                              Foreground="Teal" FontWeight="Bold">

                        vbCity.com</TextBlock>

                </Border>

            </Hyperlink>

            </TextBlock>

    I set three properties of the inner TextBlock, the Background to my LinearGradientBrush, the Foreground and FontWeight.  I set the FontWeight so that the Text of the TextBlock stands out a little more. 
    I now mostly had the look I was going for.

    I say mostly because I still had the blue line under the link showing it as a link which I didn’t want.  I also have not set the link itself.

    Setting the NavigateUri and TextDecorations properties of the Hyperlink fixes those two remaining issues.

            <TextBlock>

            <Hyperlink NavigateUri="http:\\www.vbcity.com" TextDecorations="None">

                <Border BorderBrush="{StaticResource MyBrush}"

                       BorderThickness="10" CornerRadius="20,0,10,0">

                    <TextBlock Background="{StaticResource MyBrush}"

                              Foreground="Teal" FontWeight="Bold">

                        Home</TextBlock>

                </Border>

            </Hyperlink>

            </TextBlock>

    The screenshot below shows the final look of the Hyperlinks.

  • Hyperlinks with Images and WPF Pages

     Continuing on the subject, and project, from my last post I will look at using an Image, as well as other WPF Elements, instead of plain boring Text as the visual for a Hyperlink on a WPF Page.

    The page in question will be viewed by the user in the web browser, in the instance of my application the browser will be IE6, which will link to external sites on the Internet.  We wanted to use the logo from the sites, sometimes with a caption under the logo, rather than just a textual link.

    It did take me a while to figure this one out mostly because that I forgot one of the really great things about Windows Presentation Foundation (WPF) which is that just about all WPF Controls, if not all, can hold any WPF object themselves which made setting up the Image links very easy.

    I started out with the Hyperlink itself.  Due to the fact a Hyperlink is not a UIElement I had to place the link itself in a TextBlock.

            <TextBlock>

            <Hyperlink NavigateUri="http:\\www.vbcity.com">

                Visit vbCity.com</Hyperlink>

            </TextBlock>

    The image below shows the link on the page.

    To get the image to be the Hyperlink, the XAML for the Image needs to be added between the opening and closing tags of the Hyperlink as well as removing the text of the link.

            <TextBlock>

            <Hyperlink NavigateUri="http:\\www.vbcity.com">

                <Image Source=".\vbcity_logo.jpg"></Image>

            </Hyperlink>

            </TextBlock>

     So I ended up with what I originally wanted an Image as a Hyperlink as the screenshot below shows.

    There was one other small nit-picky detail to take care of before I was finished.  If you look closely at the next screenshot, you can see a small blue line under the image indicating that the image is a link.

    I didn’t want the line under the image so I just had to set one more Property of the Hyperlink.  The property to be set is the TextDecorations Property of the Hyperlink to None.

            <TextBlock>

            <Hyperlink NavigateUri="http:\\www.vbcity.com"

                      TextDecorations="None">

                <Image Source=".\vbcity_logo.jpg"></Image>

            </Hyperlink>

            </TextBlock>

     Now you can see that there is no line under the link.

     

  • Hyperlinks and WPF Pages

    You may not think that this topic is worthy of a blog post, but I found the process interesting when the need for me to use Hyperlinks arose while working on a project.

    The project, I decided, was going to use a Windows Presentation Foundation (WPF) Page to give the User easy access to a listing of documents which reside on a shared drive.  The Page would be viewed through the Users web browser (in this case IE6) and then navigate to the document they wanted by clicking on the Hyperlink.

    Now you may be saying to yourself that this is a trivial task and, aside from design, all that was required was to add the link to the document in the NavigateUri Property of the Hyperlink.

            <!-- Absolute path of File -->

            <Hyperlink NavigateUri="file:///s:\directory1\directory2\file.doc">File 1</Hyperlink>

     

            <!-- Absolute path of Internet File -->

            <Hyperlink NavigateUri="http:\\www.neilknobbe.com">My Site</Hyperlink>

     

            <!-- Relative path of File -->

            <Hyperlink NavigateUri="file.doc">File 1</Hyperlink>

     

            <!-- Relative path of File in Sub-Directory -->

            <Hyperlink NavigateUri="subdirectory\file.doc">File 1</Hyperlink>

    Normally this would be the case, but due to the way that User Permissions were set up there was going to be two different possible Paths that the file could be found at depending on what permissions each user had.

    Most users, of the application, when they open the shared drive they are pointed to a directory which resides in a directory of the root directory on the drive.  Those with special privileges get directed to a directory one step up from the normal users.   Due to the possibility of different paths I could not use Absolute paths, like the first two Uri’s in the examples above, because I couldn’t determine which user was accessing the page.  This left me with using Relative paths for the files.

    Using Relative paths was fine to a degree if the files resided either in the same directory as the WPF Page or further down the directory tree of the directory the WPF Page was in.  In these cases I could use a path like the following.

            <!-- Relative path of File -->

            <Hyperlink NavigateUri="file.doc">File 1</Hyperlink>

     

            <!-- Relative path of File in Sub-Directory -->

            <Hyperlink NavigateUri="subdirectory\file.doc">File 1</Hyperlink>

    The majority of the files, in the case of my project, were in different directories than the WPF Page itself and as such using the previous type of Relative paths was not an option.  The WPF page was in a directory of the shared drive and all the other documents that I wanted to link to resided in their own topically named directories.

    What I needed to do was figure out how to navigate out of the WPF Page directory and into the other directories.

    In the end the answer was relatively, sorry no pun intended, simple.

    It turned out that to work up a directory tree for a Hyperlink you only need to add a full stop in front of the path for each directory up the directory tree you want to move up.

    Adding one full stop to the front of the Path sets the directory to be the directory that the Page resides in.  So I could also use the following for a file in the same directory as the Page.

            <!-- Relative path of File -->

            <Hyperlink NavigateUri=".\file.doc">File 1</Hyperlink>

    You could also use the same format for a file in a subdirectory.

            <!-- Relative path of File -->

            <Hyperlink NavigateUri=".\file.doc">File 1</Hyperlink>

    If, for example, I wanted to link to a file in a sibling directory of the directory the Page resides in then I needed to two full stops to the front of the Relative path of the file.

            <!-- Relative path of File in Sub-Directory -->

            <Hyperlink NavigateUri="..\siblingdirectory\file.doc">File 1</Hyperlink>

    As mentioned above, the first full stop sets the path to the directory that the Page resides in and each additional full stop moves one directory up the tree.

    In the case of my application the two full stops took the path up to what most users would see as the root directory of the shared drive, after that it was just a case of adding the sub-directory, or sub-directories, and the file name to complete the link.

Copyright 1998-2009 vbCity.com LLC
Powered by Community Server (Non-Commercial Edition), by Telligent Systems