Solved: black border around screen with HDMI

Sunday, October 02, 2011 / Posted by Luke Puplett / comments (0)

After purchasing 2 Benq HD2420HD for £125 each (!) from Amazon, I got a nasty black border around the image on the HMDI-connected panel.

To remove the nasty black border around the screen when a panel is connected via HDMI, set the Overscan to 0%, the menu option for ATI cards can be found here:

image

image

Labels: ,

Combining Anonymous Types with Dynamic

Sunday, September 25, 2011 / Posted by Luke Puplett / comments (0)

This short blog post shows the outcome of a quick experiment. I am researching a way to back a WPF View with a ViewModel whose properties are not known until runtime.


It’s been a long time since I last blogged. I built a house, I’ve had a baby, well, Cassie did the hard work, and also worked on a very large Silverlight project for a large investment bank (a foreign exchange trading platform) and then moved again to a start-up in the West End of London.

The former job was all hush-hush and even though our small team had the pleasure of a couple of exclusive hours with Silverlight evangelist Mike Taulty, we weren’t able to tell him what we were working on. So blogging was out of the question, which is a real shame for me and the community as a whole, in my opinion (although understandable).

The Interesting Bit
Anyway, while playing this afternoon, I discovered that anonymous types can escape the confines of the scope they’re declared in by returning them as dynamic!
Check this out:
1 static void Main(string[] args) 2 { 3 var rows = ReadDynamicRows(); 4 5 foreach (var row in rows) 6 Console.WriteLine(row.Id); 7 8 object o = rows[0]; 9 var properties = o.GetType().GetProperties(); 10 } 11 12 private static List<dynamic> ReadDynamicRows() 13 { 14 dynamic row; 15 List<dynamic> rows = new List<dynamic>(); 16 using (var reader = 17 DataHelper.ExecuteSqlStatementReader( 18 DataHelper.BuildConnectionString(), 19 "SELECT TOP 1000 * FROM SomeTable")) 20 { 21 while (reader.Read()) 22 { 23 row = new 24 { 25 Id = reader.GetString(0), 26 }; 27 28 rows.Add(row); 29 } 30 } 31 32 return rows; 33 }


What’s really interesting to me is that the properties can be reflected upon. In my experiments with the dynamic type, this isn’t true and so databinding won’t work.


I don’t believe its that simple to stick them in an ObservableCollection bound to a DataGrid because the mechanics of it uses ICustomTypeDescriptor


More to come... (have a train to catch)

Labels: , ,

Note to self: Reading extended file properties

Wednesday, January 05, 2011 / Posted by Luke Puplett / comments (0)

To read the extended file property metadata from a file, such as a the exposure of a photo or the duration of some media file, then follow these simple steps.

Download and reference the Windows API Code Pack, no link here since it changes name and version, but it easily found in Bing.

// Usings

using System;
using System.IO;
using Microsoft.WindowsAPICodePack.Shell;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;

// Method

string mediaPath = @"c:\Users\Public\Recorded TV\Shark Tale_BBC ONE_2010_12_31_14_08_00.wtv";

var file
= new FileInfo(mediaPath);

// The formatId and propertyId values can be taken from MSDN:
// http://msdn.microsoft.com/en-us/library/bb787399(v=VS.85).aspx
//
PropertyKey pk = new PropertyKey("64440490-4C8B-11D1-8B70-080036B11A03", 3);
var p
= ShellFile.FromFilePath(file.FullName).Properties.GetProperty(pk);

if (p != null)
{
Console.WriteLine(
string.Concat(p.CanonicalName, ": ", p.ValueAsObject));

UInt64 d
= (UInt64)p.ValueAsObject;
var duration
= TimeSpan.FromTicks((long)d);
}

Labels: ,

To PowerShell or Not

Friday, December 17, 2010 / Posted by Luke Puplett / comments (8)

To pull down, sort out and import the guide data for vuPlan.tv I thought it would be a good excuse to use PowerShell. I’ve been wanting to use this for ages, to get up-to-speed with what the future of scripting on MS Windows looks like.

I hated every moment of it.

This simple script took more than a whole day to write.

#
#
Looks for the latest downloaded .zip file and extracts its contents.
#

$random = new-object -typename System.Random

$dataRoot = "C:\DATA"
$sourceFolder = $dataRoot + "\EPG"
$extractRoot = $dataRoot + "\EPG\TEMP-" + $random.Next(100)
$dataRepository = $dataRoot + "\EPG\HEAP"
$unzipToolPath = $dataRoot + "\unzip.exe"
$importerToolPath = "C:\Users\Public\Documents\~Main\Vuplan\Evoq.Vuplan.Data.Epg.Importer\Evoq.Vuplan.Data.Epg.Importer\bin\Release\import.exe"

clear

set
-location $sourceFolder
#$latestFiles = get-childitem | where { $_.Name -like "*TV*" -and $_.LastWriteTime.Date -eq [DateTime]::Now.Date }
$files = get-childitem | where { $_.PSIsContainer -eq $false }
$latestFiles = $files | sort -property @{Expression={ $_.LastWriteTime }; Ascending=$false}
$latestZip = $latestFiles[0]
echo
"Extracting " + $latestZip.FullName + " to " + $extractRoot
md
$extractRoot

# This little chunk of code unzips using Windows shell but problems with the feckin .zip file mean
#
that some files extract twice and invoke a UI prompt for overwrite-replace.
#

#
$shell = new-object -com shell.application
#
$zipFile = $shell.namespace($latestZip.FullName)
#
$extractTo = $shell.namespace($extractRoot)
#
$extractTo.Copyhere($zipFile.Items())

#foreach($item in $extractTo.Items) {
#

#
$item
#
}

$processArgs = "-o " + $latestZip.FullName + " -d " + $extractRoot
$startInfo = new-object System.Diagnostics.ProcessStartInfo($unzipToolPath, $processArgs)
$startInfo.UseShellExecute = $false

$unzipProcess = new-object System.Diagnostics.Process;
$unzipProcess.StartInfo = $startInfo
$startInfo
echo
"Starting process."
$unzipProcess.Start()

while(!$unzipProcess.HasExited)
{
echo
"Waiting for process to complete..."
[System.Threading.Thread]
::Sleep(1000)
}

$sourceDirectoryInfo = new-object System.IO.DirectoryInfo($extractRoot)
foreach ($item in $sourceDirectoryInfo.GetFiles())
{
$destinationPath = [String]::Concat($dataRepository, "\", $item.Name)

if ([System.IO.File]::Exists($destinationPath) -ne $true)
{
"Copying " + $item.Name + " to the heap..."

[System.IO.File]
::Copy($item.FullName, $destinationPath)
}

if ($item.Extension -eq ".xml")
{
$processArgs = $item.FullName
$startInfo = new-object System.Diagnostics.ProcessStartInfo($importerToolPath, $processArgs)
$startInfo.UseShellExecute = $false

$importProcess = new-object System.Diagnostics.Process;
$importProcess.StartInfo = $startInfo
$startInfo
echo
"Starting import."
$importProcess.Start()

while(!$importProcess.HasExited)
{
"[" + $item.Name + "]" + " Waiting for import to complete... " + ([DateTime]::Now - $importProcess.StartTime)
[System.Threading.Thread]
::Sleep(1000)
}
}
}

$sourceDirectoryInfo.Delete($true)



It was such a disappointment. I’m still disappointed as I type this. Being a scripting environment for the .NET Framework, I thought it’d be so cool. The power of the .NET Framework and the freedom of scripting.



But the Integrated Scripting Environment (ISE) is just some crappy cobbled-together tool written in not much more time than it took me to write my script here. It even uses the atrocious code editor from the Expression suite and not the awesome editor that Noah Richards and his team made for Visual Studio 2010.



But worst of all, it has no IntelliSense. Can you imagine?



Apparently there’s PowerGUI that is a non-Microsoft ISE that does have autocomplete (which is an absolute must when you’ve all of the .NET Framework at your disposal and there’s no compiler to warn as you go), but I read something about a guy having a problem with a script which was down to the PowerGUI editor getting confused over some combination of slashes and dots, which put me right off.



So I punched my code into the MS ISE, almost single fingering the keys to ensure it was all correct, like I was back in the 1980s with my Sharp MZ-700.



And slowly my will to live drained from me.



I even read some dude praising it because all he needed was Notepad and Google to be a master of his universe. Not out of my pocket does an engineer work with such inefficiency. Would you take the cab if you saw that the driver was peddling the car through a hole in the floor?



Next time, I will do what I usually do and write a full blown console application in a tenth of the time.



If you’re a .NET developer, Hell, if you’re a sys admin (as I was for years), I’d just use Visual Studio all the way. Skip those cmdlets.



Get properly organised by writing and adding to an assembly of reusable components and classes to help you do your admin tasks. Get the whole department adding to a super cool library of administrative joy.



I came into programming from a sys admin background. I worked for a very large organisation with tens of thousands of computers. I saw the same code across so many scripts, it was a terrible duplication of effort.



So I cultivated a library of fine-grained admin tools in a COM component that was deployed to the PC estate and called from the scripts, a core set of reusable functionality. Then later I integrated it with a Microsoft Excel add-in. That’s right, sys admins could build out their scripts from a report in Excel, drag and drop, cut and paste. Done.



Anyway, I’m going off on a tangent. The benefits of PowerShell from my noob viewpoint are, simple visual remotability and a focus for vendors to create simple APIs (by way of custom cmdlets).



These things are important for the daily activities of a busy sys admin performing live commands, sure, but if its a automated or long scripted process you need to write, its not ideal.



If you’re already a programmer, then just write a proper applet in the superior tools you know and love and share it with your team. And if you’re not a programmer, skip scripting and learn C#.



Coding in Visual Studio will blow your mind and make you a hero.



Luke

Labels: ,

The World’s Best MessageBox Control (it maybe just a bog standard message box control to you but I like it)

Thursday, December 09, 2010 / Posted by Luke Puplett / comments (2)

Here it is in action, recorded on a Flip Mino HD, which really doesn’t like filming anything close-by or with fine detail. But you get the picture.

SimpleMessageBox for Windows Phone 7 from Luke Puplett on Vimeo.

The message box is a pretty straight forward affair, following the parts and states model. What’s possibly interesting is that the buttons are added as KeyValue<string, ICommand> pairs and rendered in the default template using a WrapPanel.

This means its dependant on two external libraries; Laurent Bugnion’s excellent MVVM Light Toolkit and also the Silverlight Toolkit for Windows Phone.

But the cool thing is that its entirely MVVM-able and the WrapPanel means that you can chuck as many buttons as you like on the page and they’ll look fabulous (darling).



namespace Evoq.Vuplan.Mobile.Phone.Controls
{
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Collections.Generic;
using System.Windows.Input;
using GalaSoft.MvvmLight.Command;
using System;

/// <summary>
/// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
///
/// Step 1a) Using this custom control in a XAML file that exists in the current project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:AnimationExperiments"
///
///
/// Step 1b) Using this custom control in a XAML file that exists in a different project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:AnimationExperiments;assembly=AnimationExperiments"
///
/// You will also need to add a project reference from the project where the XAML file lives
/// to this project and Rebuild to avoid compilation errors:
///
/// Right click on the target project in the Solution Explorer and
/// "Add Reference"->"Projects"->[Browse to and select this project]
///
///
/// Step 2)
/// Go ahead and use your control in the XAML file.
///
/// <MyNamespace:WindowGrip/>
///
/// </summary>
[TemplatePart(Type = typeof(TextBlock), Name = SimpleMessageBox.TitlePartName)]
[TemplatePart(Type
= typeof(TextBlock), Name = SimpleMessageBox.MessagePartName)]
[TemplatePart(Type
= typeof(ItemsControl), Name = SimpleMessageBox.ButtonItemsPartName)]
[TemplateVisualState(GroupName
= "VisibilityStates", Name = SimpleMessageBox.CollapsedStateName)] // Default
[TemplateVisualState(GroupName = "VisibilityStates", Name = SimpleMessageBox.VisibleStateName)]
public class SimpleMessageBox : Control
{
#region Fields

string _currentState = "stateSetInOnApplyTemplate";

#endregion

#region Constants

private const string TitlePartName = "TitlePart";
private const string MessagePartName = "MessagePart";
private const string ButtonItemsPartName = "ButtonItemsPart";

private const string CollapsedStateName = "Collapsed";
private const string VisibleStateName = "Visible";

#endregion

#region Dependency Property Backers

public static readonly DependencyProperty IsCollapsedProperty =
DependencyProperty.Register(
"IsCollapsed", typeof(bool), typeof(SimpleMessageBox),
new PropertyMetadata(true, new PropertyChangedCallback(HandleCollapsedChanged)));

public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register(
"Title", typeof(string), typeof(SimpleMessageBox),
new PropertyMetadata("Alert"));

public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register(
"Message", typeof(string), typeof(SimpleMessageBox),
new PropertyMetadata("You need to set a message to display, even if it is an empty string."));

public static readonly DependencyProperty ButtonsProperty =
DependencyProperty.Register(
"Buttons", typeof(ObservableCollection<KeyValuePair<string, ICommand>>), typeof(SimpleMessageBox),
new PropertyMetadata(new ObservableCollection<KeyValuePair<string, ICommand>>()));

#endregion

#region Constructors

static SimpleMessageBox()
{
// DefaultStyleKeyProperty.OverrideMetadata(typeof(StatefulImage), new FrameworkPropertyMetadata(typeof(StatefulImage)));
}

public SimpleMessageBox()
:
base()
{
DefaultStyleKey
= this.GetType();
this.Buttons = new ObservableCollection<KeyValuePair<string, ICommand>>();

if (DesignerHelper.GetIsInDesignMode())
{
this.Buttons.Add(new KeyValuePair<string, ICommand>("test", new RelayCommand(new Action(() => { }))));
}
}

#endregion

#region Properties

/// <summary>
/// Gets or sets a value that indicates whether or not the message box is collapsed.
/// </summary>
public bool IsCollapsed
{
get { return (bool)GetValue(IsCollapsedProperty); }
set { SetValue(IsCollapsedProperty, value); }
}

/// <summary>
/// Gets or sets the title of the message box.
/// </summary>
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}

/// <summary>
/// Gets or sets the message in the message box.
/// </summary>
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}

/// <summary>
/// Gets or sets a collection of the buttons on the message box.
/// </summary>
public ObservableCollection<KeyValuePair<string, ICommand>> Buttons
{
get { return (ObservableCollection<KeyValuePair<string, ICommand>>)GetValue(ButtonsProperty); }
set { SetValue(ButtonsProperty, value); }
}

#endregion

#region Methods

private static void HandleCollapsedChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var control
= (SimpleMessageBox)sender;

control.UpdateStates(
true);
}

/// <summary>
/// Reads properties and fires off the state changer using VSM.
/// </summary>
/// <param name="useTransitions">Whether to trigger animations between the states.</param>
private void UpdateStates(bool useTransitions)
{
string state = this.IsCollapsed ? CollapsedStateName : VisibleStateName;

if (_currentState != state)
{
_currentState
= state;
VisualStateManager.GoToState(
this, state, useTransitions);
}
}

void page_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel
= !this.IsCollapsed;
this.IsCollapsed = true;
}

#endregion

#region Control Overrides

public override void OnApplyTemplate()
{
base.OnApplyTemplate();

this.UpdateStates(false);

try
{
FrameworkElement p
= this;
while (!(p is PhoneApplicationPage))
p
= p.Parent as FrameworkElement;

var page
= (PhoneApplicationPage)p;
page.BackKeyPress
+= new EventHandler<System.ComponentModel.CancelEventArgs>(page_BackKeyPress);
}
catch
{ }
}

#endregion
}
}

This should be all that’s needed in the Themes\generic.xaml to set its default skin.





<ResourceDictionary
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:windows
="clr-namespace:System.Windows;assembly=System.Windows"
xmlns:local
="clr-namespace:YourControlNamespace;assembly=YourControlsAssembly"
xmlns:toolkit
="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
xmlns:i
="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd
="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP7"
xmlns:unsupported
="clr-namespace:Microsoft.Phone.Controls.Unsupported"
>
<!-- Resource dictionary entries should be defined here. -->

<Style TargetType="local:SimpleMessageBox">
<Setter Property="Background" Value="{StaticResource PhoneChromeBrush}" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SimpleMessageBox">
<Canvas>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisibilityStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.3">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseOut"/>
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Collapsed">
<Storyboard>
<DoubleAnimation Duration="0" To="-90" Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationX)" Storyboard.TargetName="MessageBoard" />
</Storyboard>
</VisualState>
<VisualState x:Name="Visible"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid x:Name="MessageBoard" Background="{TemplateBinding Background}" Width="{TemplateBinding Width}">
<Grid.Projection>
<PlaneProjection/>
</Grid.Projection>
<StackPanel Margin="15">
<TextBlock x:Name="TitlePart" FontSize="{StaticResource PhoneFontSizeLarge}" FontFamily="{StaticResource PhoneFontFamilyNormal}"
Text
="{TemplateBinding Title}" TextWrapping="Wrap" Margin="0,0,0,5" />
<TextBlock x:Name="MessagePart" FontSize="{StaticResource PhoneFontSizeMedium}" FontFamily="{StaticResource PhoneFontFamilyLight}"
Text
="{TemplateBinding Message}" TextWrapping="Wrap" Margin="0,0,0,16" />
<ItemsControl x:Name="ButtonItemsPart" ItemsSource="{TemplateBinding Buttons}" Margin="-15,0" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Horizontal" HorizontalAlignment="Left" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button MinWidth="238">
<TextBlock Text="{Binding Key}" />
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand Command="{Binding Value}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>


</ResourceDictionary>




And there are two snippets here that demonstrate the control, but are otherwise not required.





// In Page ViewModel ctor or some method.

// Tests the control by constantly transitioning.

this.MessageBox = new MessageBoxViewModel()
{
Title
= "Test run-time data",
Message
= "This message text is inserted in the constructor of the view model.",
ControlVisibility
= Visibility.Visible,
};

var exit
= new RelayCommand( () => { _t.Change(0, 0); } );

this.MessageBox.ButtonCommandPairs.Add(new KeyValuePair<string, System.Windows.Input.ICommand>("run", null));
this.MessageBox.ButtonCommandPairs.Add(new KeyValuePair<string, System.Windows.Input.ICommand>("time", exit));

_t
= new System.Threading.Timer(new System.Threading.TimerCallback((state) =>
{
_log.Debug(
"Timer");

if (this.MessageBox.IsCollapsed)
Deployment.Current.Dispatcher.BeginInvoke( ()
=> this.MessageBox.IsCollapsed = false );
else
Deployment.Current.Dispatcher.BeginInvoke(()
=> this.MessageBox.IsCollapsed = true);

}),
null, 1000, 1000);


// In ViewModel somewhere:

public MessageBoxViewModel MessageBox { get; set; }




This is the view model for the message box and is usually exposed as a property of the page’s view model (note above the this.MessageBox property being set).





namespace Evoq.Vuplan.Mobile.Phone.ViewModels
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;

public class MessageBoxViewModel : INotifyPropertyChanged
{
#region Fields

#endregion

#region Events and OnMethods

public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler
= PropertyChanged;
if (null != handler)
{
handler(
this, new PropertyChangedEventArgs(propertyName));
}
}

#endregion

#region Constructors

public MessageBoxViewModel()
{
this.ButtonCommandPairs = new ObservableCollection<KeyValuePair<string, ICommand>>();
}

#endregion

#region Properties

private string _title;
/// <summary>
/// Sample ViewModel property; this property is used in the view to display its value using a Binding.
/// </summary>
/// <returns></returns>
public string Title
{
get
{
return _title;
}
set
{
if (value != _title)
{
_title
= value;
NotifyPropertyChanged(
"Title");
}
}
}

private string _message;
/// <summary>
/// Sample ViewModel property; this property is used in the view to display its value using a Binding.
/// </summary>
/// <returns></returns>
public string Message
{
get
{
return _message;
}
set
{
if (value != _message)
{
_message
= value;
NotifyPropertyChanged(
"Message");
}
}
}

private bool _isCollapsed;
/// <summary>
/// Sample ViewModel property; this property is used in the view to display its value using a Binding.
/// </summary>
public bool IsCollapsed
{
get
{
return _isCollapsed;
}
set
{
if (value != _isCollapsed)
{
_isCollapsed
= value;
NotifyPropertyChanged(
"IsCollapsed");
}
}
}

private Visibility _controlVisibility;
/// <summary>
/// Sample ViewModel property; this property is used in the view to display its value using a Binding.
/// </summary>
/// <returns></returns>
public Visibility ControlVisibility
{
get
{
return _controlVisibility;
}
set
{
if (value != _controlVisibility)
{
_controlVisibility
= value;
NotifyPropertyChanged(
"ControlVisibility");
}
}
}

public ObservableCollection<KeyValuePair<string, ICommand>> ButtonCommandPairs { get; private set; }

#endregion
}
}


This lump of XAML shows how to declare the control on a page. The thing which is important here is to use TwoWay binding because the SimpleMessageBox control itself can change the IsCollapsed property internally when handling the back button key.





<controllib:SimpleMessageBox DataContext="{Binding MessageBox}"
Title
="{Binding Title}" Message="{Binding Message}"
Buttons
="{Binding ButtonCommandPairs}"
Width
="{Binding ElementName=LayoutRoot, Path=ActualWidth}"
IsCollapsed
="{Binding IsCollapsed, Mode=TwoWay}" />




Merry Christmas!