Delay's Blog

Silverlight, WPF, Windows Phone, Web Platform, .NET, and more...

Posts
  • Delay's Blog

    The platform giveth power, don't taketh it away [Tip: Do not assign DependencyProperty values in a constructor; it prevents users from overriding them]

    Tip

    Do not assign DependencyProperty values in a constructor; it prevents users from overriding them

    Explanation

    Initializing variables in an object's constructor is considered a Good Thing. Traditionally, initialization is done with a simple assignment that sets the variable to its initial value: MyProperty = 10;. However, doing that with a Silverlight/WPF DependencyProperty uses the CLR wrapper (more background here and here) and results in a call to SetValue that sets the local value of that property. The precedence order for DependencyProperty values is such that the local value overrides almost any other value the application may have provided with a Style (normal or implicit) Setter or Trigger. But if a property can't be styled, then much of the goodness of being a DependencyProperty goes out the window... Fortunately, there are two good alternatives; the most direct is to pass the default value in the call to Register. Setting the default value that way is nice because it's easy, it's obvious, and it "just works". And since DependencyProperty default values have the lowest precedence of anything, you don't need to worry about overriding any customizations users may have made. Next time: The other option.

    Good Example

    public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register(
        "MyProperty", typeof(int), typeof(MyControl), new PropertyMetadata(123, OnMyPropertyChanged));

    More information

  • Delay's Blog

    When you have two good options, go with the easier one [Tip: Set DependencyProperty default values in a class's default style if it's more convenient]

    Tip

    Set DependencyProperty default values in a class's default style if it's more convenient

    Explanation

    In the previous tip, I explained why it's usually wrong to assign a value to a Silverlight/WPF DependencyProperty in the constructor for a class. The preferred way is to pass the default value in the call to Register, but there's another good option: set the property's starting value in the default Style for the control by putting it in generic.xaml. A control's default style is applied when it is first created and the corresponding changes to its DependencyProperty values have very low precedence (though not as low as the default value passed to Register). Therefore, this is a safe place to set default values without the risk of overriding application-level customizations. A nice benefit of this approach is that it allows the value to be specified in XAML - which offers a designer-friendly syntax and can sometimes be easier to understand. In the example below, a rather complicated Brush is constructed in XAML; the matching code to create that same brush would not be as clear. Next time: Something to watch out for when setting default values.

    Good Example

    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:local="clr-namespace:DevelopmentTips">
        <Style TargetType="local:MyControl">
            <Setter Property="MyBrush">
                <Setter.Value>
                    <LinearGradientBrush>
                        <GradientStop Color="Red" Offset="0"/>
                        <GradientStop Color="Green" Offset="0.5"/>
                        <GradientStop Color="Blue" Offset="1"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>

    More information

  • Delay's Blog

    Highlighting a "weak" contribution [Enhancements make preventing memory leaks with WeakEventListener even easier!]

    It was back in March of last year that I explained the motivation for the WeakEventListener class I'd started using in the Silverlight Toolkit's Data Visualization assembly. Since then, a few other Toolkit controls have added WeakEventListener where necessary - but otherwise not much has changed...

    Then, a few days ago, I saw that Beat Kiener had written a post detailing the specifics of how WeakEventListener really works. Where I focused more on saying why WeakEventListener is necessary, Beat does a great job of showing why - with lots of pretty diagrams and a detailed explanation. He even identifies a mistake users of WeakEventListener might make and outlines a simple tweak to the original implementation to prevent it! Beat's post is a good read, and I recommend it for anyone who's interested in this stuff.

    But wait, there's more! Beat followed with a post about a wrapper to simplify the common usage pattern shared by every WeakEventListener consumer. Whereas WeakEventListener is a little tricky to use correctly, Beat's wrapper is easy to get right - and still gets the job done! So if you've wanted to make use of WeakEventListener, but were intimidated by the technical details, please have a look at these two posts because I think you'll find it's really quite approachable. :)

     

    PS - If you think you have a memory leak, but aren't sure, this post I wrote about using WinDbg, SOS, and GCRoot to diagnose .NET memory leaks may be helpful.

  • Delay's Blog

    Going dark [MSDN blogging platform being upgraded - NO new posts or comments next week]

    The administrators of the MSDN blogging platform are performing a software upgrade and will be putting all blogs into read-only mode on Sunday, May 16th. New posts and new comments will not be possible for this blog during the transition. The upgrade is expected to finish by Monday, May 24th - but difficulties during the migration could push that date back. I'll post a quick note once the dust has settled and things are back to normal.

    In the meantime, you should be able to contact me using the old platform's email form. Alternatively, I can be reached on Twitter as @DavidAns.

    Thank you for your patience - see you on the other side! :)

  • Delay's Blog

    If found, please return to... [Using XAML to create a custom wallpaper image for your mobile device]

    Background

    These days it seems like everybody has a mobile device with them practically all the time. It's pretty amazing that we're able to be "always connected" - technology has made great progress! However, humankind hasn't changed nearly as quickly, and occasional forgetfulness is still a part of everyone's life. :) So it's fairly common that someone forgets their device in a meeting room, drops it out of their pocket on the bus, or otherwise misplaces it. What's to be done?

    Well, there are all kinds of high-tech approaches like GPS location services, network-based tracking, and the like. But sometimes a low-tech solution works, too! In particular, just slapping a label with your name and phone number on the back is probably enough to get a lost device returned when someone finds it. But that's really low-tech - and besides, some people don't want to mar the shiny surface of their pretty hardware with stickers, etchings, and the like...

     

    One solution

    I propose a mid-tech approach. It begins with the observation that most mobile devices allow you to customize the default wallpaper image. Because "pixels is pixels", it's clear the custom wallpaper image could include text - and that text is perfect for our purposes! Creating a custom wallpaper is quite easy and leads to a nice, attractive experience like this:

    Custom wallpaper on an iPod touch

    The example above uses an iPod touch (it's an iPhone without the phone), but the concept applies to any device that allows you to customize the login screen wallpaper (even laptops!).

     

    One implementation

    Creating a custom wallpaper can be done in lots of different ways. For the purposes of this exercise, I wanted complete control over the layout, high quality graphics, and a flexible, hierarchical, vector-based approach. The answer was obvious: XAML! :)

    So I created a simple WPF application and added some scaffolding to represent the size of the device and the placement of its UI overlays. (Aside: I could have used Silverlight, too; WPF seemed like it might make the image capture step a smidge easier.) With that framework in place, it was easy to create the custom content you see here with an image, some layout containers, and some text. The resulting MobileDeviceHomeScreenMaker application looks like this (and I mean exactly like this: no title, no borders, etc.):

    Custom wallpaper application

    From there, it's easy to get the custom wallpaper onto the device:

    1. Left-click on the MobileDeviceHomeScreenMaker window to hide the overlays
    2. Press Alt+Print Screen to copy the foreground window to the clipboard
    3. Paste it into your favorite graphics program (I used Windows Paint)
    4. Save the image to a file (I used the lossless PNG format)
    5. Transfer that image to the device (with a dedicated sync program, by surfing to it on the web, etc.)
    6. Tell the device to use the custom image as its wallpaper (in the settings app, from the photo viewer, etc.)

    It's really that easy! All that's left is to...

    [Click here to download the complete MobileDeviceHomeScreenMaker .NET 4 application as a Visual Studio 2010 solution.]

     

     

    The XAML

    <!--
    MobileDeviceHomeScreenMaker
    http://blogs.msdn.com/delay/
    -->
    
    <Window x:Class="MobileDeviceHomeScreenMaker.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MobileDeviceHomeScreenMaker"
            SizeToContent="WidthAndHeight"
            ResizeMode="NoResize"
            WindowStyle="None"
            WindowStartupLocation="CenterScreen"
            Background="Black">
    
        <!-- Frame -->
        <Grid Height="480" Width="320">
            <Grid.RowDefinitions>
                <RowDefinition Height="116"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="96"/>
            </Grid.RowDefinitions>
    
            <!-- Instructional ToolTip -->
            <ToolTipService.ToolTip>
                <ToolTip>
                    <StackPanel>
                        <TextBlock Text="Left-click toggles overlay"/>
                        <TextBlock Text="Right-click closes window"/>
                        <TextBlock Text="Alt-PrintScreen captures"/>
                    </StackPanel>
                </ToolTip>
            </ToolTipService.ToolTip>
    
            <!-- Overall background -->
            <Grid.Background>
                <ImageBrush
                    ImageSource="C:\Users\Public\Pictures\Sample Pictures\Tulips.jpg"
                    Stretch="UniformToFill"
                    Opacity="0.9"/>
            </Grid.Background>
    
            <!-- Top and bottom overlays -->
            <Label
                x:Name="TimeOverlay"
                Grid.Row="0"
                Background="#80808080"
                Content="Time"
                HorizontalContentAlignment="Center"
                VerticalContentAlignment="Center"
                Foreground="White"
                FontSize="40"
                FontWeight="Bold"/>
            <Label
                x:Name="SlideOverlay"
                Grid.Row="2"
                Background="#80808080"
                Content="Slide"
                HorizontalContentAlignment="Center"
                VerticalContentAlignment="Center"
                Foreground="White"
                FontSize="40"
                FontWeight="Bold"/>
    
            <!-- Container for content -->
            <Grid
                Grid.Row="1">
    
                <Grid
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center">
                    <StackPanel
                        TextBlock.Foreground="White"
                        TextBlock.FontSize="16"
                        TextBlock.FontFamily="Segoe UI Light"
                        TextOptions.TextHintingMode="Fixed"
                        TextOptions.TextRenderingMode="Grayscale">
                        <StackPanel.Effect>
                            <DropShadowEffect
                                BlurRadius="2"
                                ShadowDepth="1"
                                RenderingBias="Quality"/>
                        </StackPanel.Effect>
                        <TextBlock
                            Text="mobile user"
                            FontSize="28"
                            FontFamily="Segoe UI Semibold"/>
                        <Grid Height="12"/>
                        <TextBlock
                            Text="mobile.user@example.com"/>
                        <Grid Height="12"/>
                        <TextBlock
                            Text="+1 (555) 555-5555"/>
                        <Grid Height="12"/>
                        <TextBlock
                            Text="One Mobile Way"/>
                        <TextBlock
                            Text="Mobile Town, MO 12345"
                            Margin="0 -2 0 0"/>
                    </StackPanel>
                </Grid>
    
            </Grid>
        </Grid>
    </Window>
  • Delay's Blog

    Q: How do you eat an elephant? A: One bite at a time... [Announcing a new "Development Tips" series on my blog!]

    With all that's going on lately, more and more people are moving their development efforts to Silverlight and WPF. What's nice is that there are already a lot of great resources available to help developers learn the basics of Silverlight and WPF programming. Whether you prefer books, videos, blogs, etc., there's no shortage of material out there to help you get started!

    But what about the next stage? What do you do to learn the finer points of the platform? The subtle nuances? The tricks? The traps??

    One of my goals for this blog is to help intermediate and advanced developers shed their inhibitions and get more intimately involved with the platform. Therefore, many of my posts push the boundaries or do things in ways that might not be completely obvious to a newcomer. But there's another facet to becoming a proficient developer - learning best practices and incorporating them into your daily routine. To that end, I'll be doing a new series of posts tagged "Development Tips"!

    The idea is that each tip will include a short, clear directive, a brief, easy to understand explanation, a simple example, and a few links to more information. Some of the tips are bound to be things just about everyone knows, while others will probably be new to some of you. Some can be found in the documentation for the platform, but others will be simple conventions that have been found to make life easier. And though there are exceptions to every rule, I won't be calling them out because I want to keep the recommendations clear and concise.

    I'm going to try to avoid controversial topics, but it would be silly not to expect some discontent every now and then. :) If you disagree with something I've written, please leave a comment explaining why you disagree what you recommend instead. I'll follow up on comments like that and if there are enough people who call me out on something, I'll revisit the topic in a new post highlighting the controversy. Of course, I'm not claiming that anything I recommend is definitively the best technique! Every situation is different and everyone has their own favorite ways of doing things. Rather, I'd like to share some tips that I've found to work well in my experience - and that seem likely to help others in similar situations.

    Okay, enough boring background already - the next post will be the first of the Development Tips!

     

    PS - That link in the previous sentence takes you to my blog's tag filter for "Development Tips". I'll tag every tip like that so it will be easy to see them all in one place.

  • Delay's Blog

    "I would prefer even to fail with honor than to win by cheating" [Tip: For a truly read-only custom DependencyProperty in Silverlight, use a read-only CLR property instead]

    Tip

    For a truly read-only custom DependencyProperty in Silverlight, use a read-only CLR property instead

    Explanation

    My last tip outlined the best way I knew to approximate a WPF-like read-only DependencyProperty on Silverlight. (Aside: It's also a good way to implement coercion.) However, it suffers from the unavoidable problem that the actual DependencyProperty is still writable and can "twitch" if written to. The comments for that post proved to be very interesting - with two suggestions for alternate techniques. I looked into them both (and stumbled across a third myself) to understand their merits. Unfortunately, the technique I stumbled across and the one Morten Nielsen (SharpGIS) suggested both suffer from this same issue: the DependencyProperty is still writable and there are ways to sneak around the protections and write to it anyway. (Aside: Morten's solution is fiendishly clever and well worth having a look at.) However, the technique suggested by Dr. WPF doesn't have that limitation - it produces a guaranteed read-only property. The catch is that it's not actually a DependencyProperty! However, Dr. WPF points out that a read-only DependencyProperty doesn't actually need to be a DependencyProperty as long as the class implements INotifyPropertyChanged. What's great is that there's no loss of functionality with the implementation shown below, and no need to try to subvert the platform! The thing to remember is that you can't use TemplateBinding to get at it - you'll need to use Binding + RelativeSource instead. Overall, this is a very nice solution - even if it does bend the rules just a bit... :)

    Good Example

    public class MyControl : Control, INotifyPropertyChanged
    {
        public int MyReadOnly
        {
            get { return _myReadOnly; }
            protected set
            {
                if (value != _myReadOnly)
                {
                    int oldValue = _myReadOnly;
                    _myReadOnly = value;
                    OnMyReadOnlyChanged(oldValue, _myReadOnly);
                    PropertyChangedEventHandler handler = PropertyChanged;
                    if (null != handler)
                    {
                        handler.Invoke(this, new PropertyChangedEventArgs("MyReadOnly"));
                    }
                }
            }
        }
        private int _myReadOnly;
        protected virtual void OnMyReadOnlyChanged(int oldValue, int newValue)
        {
            // TODO: Handle property change
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
    <ControlTemplate TargetType="local:MyControl">
        <ContentControl Content="{Binding MyReadOnly, RelativeSource={RelativeSource TemplatedParent}}"/>
    </ControlTemplate>

    More information

Page 28 of 28 (277 items) «2425262728