Brent Stewart

Live life on purpose

Setting different wallpapers for multiple monitors in Windows 10

My current development rig includes my Surface Book and two external monitors and it always bugged me that I couldn’t setup different wallpapers on each monitor.  So I did a little research and found out, that while it is not obvious, Microsoft did provide a way to make it happen without the need of any third party software.

Step 1: Multi-select (ctrl-click) the photos you want to use and right click one of them and select “Set as Desktop Background.” Your pictures should now be distributed across you monitors,

image

Step 2:  Open the Run command by right clicking the Start Icon and selecting Run.  Then type “control /name Microsoft.Personalization /page pageWallpaper” in the Run dialog and click OK.  This is a hidden page that cannot be accessed from the control panel.

image

Step 3: Click the Clear All button to deselect all pictures (this prevents windows from cycling through the select pictures).  Then you can right click on each picture and assign it to the monitor of your choice.

image

Don't Be Perfect

Always striving for perfection...sounds like a good thing...right? There may be times when the struggle to achieve perfection is good, but I find that most of the time it is a hindrance in my career. Most agree that you often learn the most from your mistakes, but the very nature of a perfectionist is that they fear making mistakes. Don't get me wrong, I make plenty of mistakes, but I find it hard to willingly go down a path that I am not sure is the correct one. I must make concerted efforts to not get stuck in endless loops of planning, designing and gold plating my software. My biggest struggle on a new project is getting out of the starting gate. My perfectionist nature wants to have every aspect of the app defined and understood to the nth degree. I don't want to start on something because I know as soon as I do, I will see the problems and have to re-work my beautiful code over and over until it is a mass of unintelligible spaghetti code that makes me want to cry. The easiest way for me to get past this is to convince myself that I am first going to write a prototype that I will throw away when I understand what is needed. Even though I know that there is a very slim chance that I will ever just toss aside the code and start from scratch, it is a metal release that gives me the freedom to make the mistakes I need and to start cranking out code without the mental handcuffs of perfectionism. Following this pattern has forced me to learn to refactor intelligently and taught me the things that are difficult to refactor and should be considered before jumping in. Cleanly refactoring is a separate skill set and will take time to learn to do well, but it is a valuable one and well worth the time spent. Don't let a desire for perfection stop you from trying, for an imperfect thing is almost always better than a perfect nothing.

Debugging wierd SQL connection issue

I had a strange SQL server connection issue the other day, and I thought I would document it.  I started working at a new client's site and needed to connect to their SQL server.  At first everything seemed to work fine, but after I left the connection idle for a while I would lose the connection and could only reconnect if I rebooted my machine.  After struggling with the problem for a couple of days I discovered I could reset my network adapter a few times and be able to reconnect to the server.  After getting tired of jumping through these hoops just to get some work done, I dove in deeper and finally discovered that the SQL server was resolving to a different IP address when it was having problems.  I put an entry for the SQL server in my HOSTS file and BAM everything was working.  I reported this to the client's IT department and sure enough there was a problem with their DNS server.  So just keep the DNS in mind if you are ever having intermittent connectivity problems.

Using Twilio to connect with you users

I have known about Twilio for a while and had been looking for an excuse to play with the awesome Phone/SMS integration service they provide.  So when I decided to write a raffle check in application for my local .NET user group, I thought that this would be a great opportunity play with their service.  Setting up integration with Twilio was very straight forward.  First I picked a phone number, loaded some money onto my Twilio account, and configured my phone number's SMS to point to my REST service.  So far the response to the check in system has been quite positive.  Before we were using the meetup responses to generate a list of users for our raffle, but there were always a few who hadn't responded on meetup, and a lot who didn't show even though they indicated they were coming.  This always resulted in wasted time in gathering the extra names and endless rounds of calling out names that weren't there.  The new system is dead simple, I write my Twilio phone number on the board and tell everyone to text their first name to it, and then everyone is entered into the raffle system.  I love when a tool removes friction, and Twilio definitely did that for me with this project.

Add PlaceHolder text to a PasswordBox

Place holder text is UI candy that makes your app feel more polished and helps users better understand what needs to be entered into fields.  I had wanted to add place holder text to my WPF app’s login screen for quite a while, but never seem to find the time.

So today I decided to figure out what needed to be done to make this happen. After some searching and reading, I discovered that there are quite a few examples on how to add PlaceHolder text to TextBox controls, but that adding PlaceHolder text to PasswordBox controls is a little more difficult.  Most  of the examples of adding PlaceHolder text to TextBox controls relied on control triggers that checked the Text property to determine the visibility of the place holder text.  The problem with using this technique on a PasswordBox control is that the PasswordBox does not expose a dependency property for the password value, so there is no simple way to wire a trigger up to the value of a PasswordBox.  After some head scratching and a little more research, I decided that using an Attached Property would allow me to accomplish what I wanted.  First, I created a PlaceHolderHelper class that contains an Attached Property PlaceHolderText and a Dependency Property, HasPassword

public class PlaceHolderHelper : DependencyObject
{
    #region PlaceHolderText
    public static bool GetPlaceHolderText(DependencyObject obj)
    {
        return (bool)obj.GetValue(PlaceHolderTextProperty);
    }
    public static void SetPlaceHolderText(DependencyObject obj, string value)
    {
        obj.SetValue(PlaceHolderTextProperty, value);
    }
    public static readonly DependencyProperty PlaceHolderTextProperty =
        DependencyProperty.RegisterAttached("PlaceHolderText", typeof(string), 
            typeof(PlaceHolderHelper), 
            new UIPropertyMetadata(string.Empty, PlaceHolderTextChanged));
    private static void PlaceHolderTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is PasswordBox)) return;
        ((PasswordBox)d).PasswordChanged += 
            (sender, args) =>
            {
                var pb  = sender as PasswordBox;
                pb.SetValue(HasPasswordProperty, (pb.Password.Length > 0));
            };
    }
    #endregion
    #region HasPassword
    public bool HasPassword
    {
        get { return (bool)GetValue(HasPasswordProperty); }
        set { SetValue(HasPasswordProperty, value); }
    }
    private static readonly DependencyProperty HasPasswordProperty =
        DependencyProperty.RegisterAttached("HasPassword",  
            typeof(bool), typeof(PlaceHolderHelper), 
            new FrameworkPropertyMetadata(false));
    #endregion
}

This let me bind up a listener to the PasswordChanged event of the PasswordBox so I could track whether a password had been entered or not.  It also gave me the needed Dependency Property to use in my Control Trigger.  Next, I needed to create a Style that overlaid my place holder text over the PasswordBox.

<Style TargetType="{x:Type PasswordBox}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type PasswordBox}">                    
                <Border Name="MainBorder"
                     Background="{TemplateBinding Background}"
                     BorderBrush="{TemplateBinding BorderBrush}"
                     BorderThickness="{TemplateBinding BorderThickness}">
                    <Grid>
                        <ScrollViewer x:Name="PART_ContentHost" VerticalAlignment="Center" Margin="1" />
                            <TextBlock x:Name="PlaceHolder"
                                Text="{TemplateBinding ctrls:PlaceHolderHelper.PlaceHolderText}" 
                                Foreground="LightGray" IsHitTestVisible="False" 
                                HorizontalAlignment="Left" VerticalAlignment="Center" Margin="4,0,0,0"/>
                    </Grid>
                </Border>                        
                <ControlTemplate.Triggers>
                    <Trigger Property="ctrls:PlaceHolderHelper.HasPassword" Value="True">
                        <Setter TargetName="PlaceHolder" Property="Opacity" Value="0" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

This is a very simplified style, but I wanted to boil this all down to the simplest example I could so you could see how this technique works.  Now all I had to do was declare a PasswordBox and set the PlaceHolderText.

<StackPanel VerticalAlignment="Top" Orientation="Horizontal" Margin="5">
  <PasswordBox Width="120" Height="24" ctrls:PlaceHolderHelper.PlaceHolderText="Enter your password" />
  <PasswordBox Width="140" Height="24" ctrls:PlaceHolderHelper.PlaceHolderText="Enter your secret phrase"  Margin="5"/>
  <Button Content="Submit" Width="50" Height="24" />
</StackPanel>

Here are the results, first with no text entered

and finally when entering text