Pages

Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Saturday, 10 March 2012

Simple WPF ColorPicker ComboBox

I needed a ColorPicker that could be embedded in a DataGrid, simple to operate and could save the color name in the database. A ComboBox seemed the obvious choice.
A simple list of colors is reasonably straightforward using a little Reflection:
      public List<string> SimpleColorList
      {
         get
         {
            List<string> colorList = new List<string>();
            foreach (PropertyInfo pi in typeof(Colors).GetProperties())
            {
               colorList.Add(pi.Name);
            }
            return colorList;
         }
      }
And bound it to a ComboBox. Using Mode=OneTime means the ColorList is only built once.
<ComboBox ItemsSource="{Binding Path=SimpleColorList, Mode=OneTime}"
            SelectedValue="{Binding SelectedColor}"
            Width="200" />
Adding a ItemTemplate to the ComboBox makes it a little more interesting:
<ComboBox ItemsSource="{Binding Path=SimpleColorList, Mode=OneTime}"
            SelectedValue="{Binding SelectedColor}"
            Width="200">
   <ComboBox.ItemTemplate>
      <DataTemplate>
         <StackPanel Orientation="Horizontal">
            <TextBlock Width="130"
                        Text="{Binding}" />
            <Border BorderBrush="Black"
                     BorderThickness="1"
                     CornerRadius="4"
                     Margin="0,1,0,1"
                     Background="{Binding}"
                     Width="40"
                     Height="18">
            </Border>
         </StackPanel>
      </DataTemplate>
   </ComboBox.ItemTemplate>
</ComboBox>
The straight alphabetic sorted list is fine but I wanted to sort by "color", in general terms from lighter to darker. I found some code on the web that would convert the RGB into the HSL color space. (I'm afraid I can't find the code again so my apologies to its author for the lack of attribution).
   public static class HslValueConverter
   {
      /// <summary>
      /// Converts a WPF RGB color to an HSL color
      /// </summary>
      /// <param name="rgbColor">The RGB color to convert.</param>
      /// <returns>An HSL color object equivalent to the RGB color object passed in.</returns>
      public static HslColor RgbToHsl(string name, Color rgbColor)
      {
         // Initialize result
         var hslColor = new HslColor();
         hslColor.Name = name;

         // Convert RGB values to percentages
         double r = (double)rgbColor.R / 255;
         var g = (double)rgbColor.G / 255;
         var b = (double)rgbColor.B / 255;
         var a = (double)rgbColor.A / 255;

         // Find min and max RGB values
         var min = Math.Min(r, Math.Min(g, b));
         var max = Math.Max(r, Math.Max(g, b));
         var delta = max - min;

         /* If max and min are equal, that means we are dealing with 
          * a shade of gray. So we set H and S to zero, and L to either
          * max or min (it doesn't matter which), and  then we exit. */

         //Special case: Gray
         if (max == min)
         {
            hslColor.Hue = 0;
            hslColor.Saturation = 0;
            hslColor.Lightness = max;
            return hslColor;
         }

         /* If we get to this point, we know we don't have a shade of gray. */

         // Set L
         hslColor.Lightness = (min   max) / 2;

         // Set S
         if (hslColor.Lightness < 0.5)
         {
            hslColor.Saturation = delta / (max   min);
         }
         else
         {
            hslColor.Saturation = delta / (2.0 - max - min);
         }

         // Set H
         if (r == max) hslColor.Hue = (g - b) / delta;
         if (g == max) hslColor.Hue = 2.0   (b - r) / delta;
         if (b == max) hslColor.Hue = 4.0   (r - g) / delta;
         hslColor.Hue *= 60;
         if (hslColor.Hue < 0) hslColor.Hue  = 360;

         // Set A
         hslColor.Alpha = a;

         // Set return value
         return hslColor;

      }
   }
   public struct HslColor
   {
      public string Name { get; set; }
      public double Alpha;
      public double Hue;
      public double Lightness;
      public double Saturation;
   }
Then I changed the property (Note: the property name has changed to SortedColorList, so the ComboBox Binding will have to be altered) "getter" to sort by Saturation, Hue and Lightness. I also decided to exclude the Transparent color.
      public List<string> SortedColourList
      {
         get
         {
            List<HslColor> colorList = new List<HslColor>();
            foreach (PropertyInfo pi in typeof(Colors).GetProperties())
            {
               Color color = (Color)pi.GetValue(null, null);
               // Only select non-Transparent colors
               if (color.A != 0) colorList.Add(HslValueConverter.RgbToHsl(pi.Name, color));
            }
            return colorList.OrderBy(c => c.Saturation)
                         .OrderBy(c => c.Hue)
                         .OrderByDescending(c => c.Lightness)
                         .Select(c => c.Name).ToList<string>();
         }
      }
The SimpleColorPicker project is available on GoogleCode.

Saturday, 3 March 2012

DataType instead of DataTemplateSelector

Nearly three years ago I posted about the use of the DataTemplateSelector.
It transpires that because I was using different types of objects in my ItemsSource I could have used the DataType attribute of the DataTemplate.
Define the DataTemplates in the usual way but add the DataType attribute.
      <DataTemplate DataType="{x:Type dts:BookingLineItem}">
      <DataTemplate DataType="{x:Type dts:CCardPaymentLineItem}">
      <DataTemplate DataType="{x:Type dts:CashPaymentLineItem}">
      <DataTemplate DataType="{x:Type dts:LineItem}">
There is no need to define the DataTemplateSelector in the resources, no C# class to write and the ListBox becomes simpler:
      <ListBox Name="theSecondTillRoll"
               Height="150"
               Width="330"
               ItemsSource="{Binding SaleItems}" />
The DataTemplateSelector project is on GoogleCode and demonstrates both techniques.

Friday, 2 March 2012

WPF String Formatting

There are a number of ways to use formatted strings and we seem to use nearly all of them in our application. Because the format of the formatting string varies slightly I thought I'd document the different techniques.
Firstly we need some simple properties for the XAML Bindings. Notice that the ToString version needs neither the index (0:) or the curly braces.
public partial class MainWindow : Window
{
   public String FormattedDate
   {
      get { return String.Format("{0:dd MMM yyy}", DateTime.Now); }
   }
   public String DateToString
   {
      get { return DateTime.Now.ToString("dd MMM yyy"); }
   }
   public DateTime RawDateTime
   {
      get { return DateTime.Now; }
   }
   public MainWindow()
   {
      InitializeComponent();
      DataContext = this;
   }
}
The first two TextBlocks bind directly to the pre-formatted properties.
      <TextBlock Text="{Binding FormattedDate}" />
      <TextBlock Text="{Binding DateToString}" />
Or we can bind to the raw data and use StringFormat. We can escape the curly braces in a couple of ways.
      <TextBlock Text="{Binding Path=RawDateTime, StringFormat=\{0:dd MMM yyyy\}}" />
      <TextBlock Text="{Binding Path=RawDateTime, StringFormat={}{0:dd MMM yyyy}}" />
The leading curly braces in the second version can be replaced by constant text that is rendered as part of the formatted string. But it seems a bit "sensitive" so I don't use it.
      <TextBlock Text="{Binding Path=RawDateTime, StringFormat=Today is {0:dd MMM yyyy}}" />
Next up is a Converter for which we need an IValueConverter class:
class DateConverter : IValueConverter
{
   public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
   {
      if (value is DateTime)
      {
         return ((DateTime)value).ToString("dd MMM yyy");
      }
      return value;
   }

   public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
   {
      throw new NotImplementedException();
   }
}
And the corresponding XAML to use the Converter:
        xmlns:local="clr-namespace:WpfWaltz"
...
   <Window.Resources>
      <local:DateConverter x:Key="dateConverter"; />
   </Window.Resources>
...
      <TextBlock Text="{Binding Path=RawDateTime, Converter={StaticResource dateConverter}}" />
Finally, I had assumed that the indexer in the StringFormat was just a necessary evil since it was always 0: and hadn't considered using StringFormat with a MultiBinding like this:
      <TextBlock>
         <TextBlock.Text>
            <MultiBinding StringFormat="{}{0:dd MMM yyyy} {1:hh:mm:ss}">
               <Binding Path="RawDateTime" /> 
               <Binding Path="RawDateTime" />
            </MultiBinding>
         </TextBlock.Text>
      </TextBlock>
The StringFormatting project that has all the code can be downloaded from GoogleCode.

Wednesday, 29 February 2012

DataGrid loading message User Control

The DataGrid loading message I created was pretty straightforward and easy to replicate in other DataGrids. But that isn't the WPF way. So instead I spent many happy hours converting into a User Control.

The Specification
Whilst the dataset is being retrieved display a "loading" message.
Once the dataset load is complete if there are no suitable records to list display a "empty dataset" message.

Executive Summary
Skip the details and download the source from GoogleCode.

The Implementation
Starting with a new User Control and adding two dependency properties to store the "loading" and "empty dataset" messages.
   public partial class DataGridProgressBar : UserControl
   {
      public readonly static DependencyProperty LoadingMessageProperty =
         DependencyProperty.Register(
            "LoadingMessage",
            typeof(string),
            typeof(DataGridProgressBar));

      public readonly static DependencyProperty EmptyDatasetMessageProperty =
         DependencyProperty.Register(
            "EmptyDatasetMessage",
            typeof(string),
            typeof(DataGridProgressBar));

      public string LoadingMessage
      {
         get { return (string)GetValue(LoadingMessageProperty); }
         set { SetValue(LoadingMessageProperty, (string)value); }
      }
      public string EmptyDatasetMessage
      {
         get { return (string)GetValue(EmptyDatasetMessageProperty); }
         set { SetValue(EmptyDatasetMessageProperty, (string)value); }
      }
   }
Next the user control needs to know the state of the dataset loading and the number of records in the dataset.
So time to add another couple of dependency properties.
      public readonly static DependencyProperty RecordCountProperty = 
         DependencyProperty.Register(
            "RecordCount", 
            typeof(long), 
            typeof(DataGridProgressBar));
      
      public readonly static DependencyProperty LoadInProgressProperty = 
         DependencyProperty.Register(
            "LoadInProgress", 
            typeof(bool?), 
            typeof(DataGridProgressBar));

      public long RecordCount
      {
         get { return (long)GetValue(RecordCountProperty); }
         set { SetValue(RecordCountProperty, (long)value); }
      }

      public bool? LoadInProgress
      {
         get { return (bool?)GetValue(LoadInProgressProperty); }
         set { SetValue(LoadInProgressProperty, (bool?)value); }
      }
Next we turn our attention to the XAML for the new User Control, remembering to add a namespace reference:
<UserControl x:Class="DataGridWatermark.DataGridProgressBar"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:local="clr-namespace:DataGridWatermark">
The actual control consists of just a single, named, TextBlock:
<UserControl .......

   <TextBlock x:Name="PART_Message" />
</UserControl>
All the hard work is done in the Style which has three main parts:
1) Initial / default style
2) Changes to the style in the Data Loading state
3) Changes to the style when there is no data to be shown.

The initial style hides the TextBlock by setting its Visibility to Collapsed, a Red font and binds to the LoadingMessage property.
      <Style TargetType="{x:Type TextBlock}">
         <Setter Property="Visibility"
                 Value="Collapsed" />
         <Setter Property="Foreground"
                 Value="Red" />
         <Setter Property="Text"
                 Value="{Binding LoadingMessage}"; />
...
      </Style>
We use a DataTrigger to detect the data loading state by binding to the LoadInProgress property and changing the Visibility from Collapsed to Visible.
         <Style.Triggers>
            <DataTrigger Binding="{Binding LoadInProgress}"
                         Value="true">
               <Setter Property="Visibility"
                       Value="Visible" />
            </DataTrigger>
...
         </Style.Triggers>
The empty dataset is a little more complicated because there are two conditions that need to be satisfied before the Empty Dataset message is displayed. The two conditions are specified inside a MultiDataTrigger.
            <MultiDataTrigger>
               <MultiDataTrigger.Conditions>
                  <Condition Binding="{Binding RecordCount}"
                             Value="0" />
                  <Condition Binding="{Binding LoadInProgress}"
                             Value="false" />
               </MultiDataTrigger.Conditions>
               <Setter Property="Foreground"
                       Value="Silver" />
               <Setter Property="Text"
                       Value="{Binding EmptyDatasetMessage}" />
               <Setter Property="Visibility"
                       Value="Visible" />
            </MultiDataTrigger>
The final piece of the jigsaw is providing a DataContext for the property bindings. I chose to explicitly set the DataContext in the code-behind in the constructor.
public DataGridProgressBar()
{
   InitializeComponent();
   PART_Message.DataContext = this;
}
And finally we can add it to the original DataGrid.
<Window x:Class="DataGridWatermark.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:uc="clr-namespace:DataGridWatermark"
...
      <DataGrid>
         <DataGrid.Background>
            <VisualBrush Stretch="None">
               <VisualBrush.Visual>
                  <StackPanel>
                     <uc:DataGridProgressBar LoadingMessage="Loading..."
                                             EmptyDatasetMessage="No Records Found"
                                             RecordCount="{Binding Path=TheRecordCount}"
                                             LoadInProgress="{Binding Path=TheLoadState}" />
                  </StackPanel>
               </VisualBrush.Visual>
            </VisualBrush>
         </DataGrid.Background>
...
</Window>

Saturday, 25 February 2012

Datagrid loading message and VisualBrush

I have to load a DataGrid from a slow running DB query. To keep the UI responsive I'm running the data retrieval on a worker thread but I wanted an inobtrusive message to be displayed to the User during the loading phase. I replaced the DataGrid's Background with a TextBlock contained in VisualBrush. With the TextBlock's Text and Visibility bound to the underlying ViewModel. For those cases where there is no data to be shown in the DataGrid I show an alternate message.
<DataGrid ItemsSource="{Binding Source{StaticResource ViewModel},Path=EnrolledStudents}"
            CanUserAddRows="False"
            CanUserDeleteRows="False"
            AutoGenerateColumns="False"
            IsReadOnly="True">
   <DataGrid.Background>
      <VisualBrush Stretch="None">
         <VisualBrush.Visual>
            <StackPanel Background="White">
               <TextBlock HorizontalAlignment="Center"
                           VerticalAlignment="Center"
                           FontSize="10pt"
                           Margin="2"
                           Foreground="Red"
                           Text="{Binding Path=Strings.V_LabelLoading}"
                           Visibility="{Binding Source{StaticResource ViewModel}, Path=EnrolledStudentLoadingInProgress, Converter={StaticResource boolToCollapsedVisibilityConverter}}" />
               <TextBlock HorizontalAlignment="Center"
                           VerticalAlignment="Center"
                           FontSize="10pt"
                           Margin="2"
                           Foreground="Silver"
                           Text="{Binding Path=Strings.V_LabelNoEnrolledStudents}"
                           Visibility="{Binding Source{StaticResource ViewModel}, Path=NoEnrolledStudents, Converter={StaticResource boolToCollapsedVisibilityConverter}}" />
            </StackPanel>
         </VisualBrush.Visual>
      </VisualBrush>
   </DataGrid.Background>
   <DataGrid.Columns>

Wednesday, 15 February 2012

SplitCSV an extension method to read CSV files

Hard on the heels on Paul's SortableStringValue I thought I would convert 'h.brouwer's Regex CSV splitter into an extension method. I've also added a couple of options to bring it in line with the standard String.Split() method.
public static class Extensions
{
   public static string[] SplitCsv(this string line)
   {
      return SplitCsv(line, int.MaxValue, StringSplitOptions.None);
   }
   public static string[] SplitCsv(this string line, int count)
   {
      return SplitCsv(line, count, StringSplitOptions.None);
   }
   public static string[] SplitCsv(this string line, StringSplitOptions options)
   {
      return SplitCsv(line, int.MaxValue, options);
   }
   public static string[] SplitCsv(this string line, int count, StringSplitOptions options)
   {
      return (from Match m in Regex.Matches(line,
      @"(((?<x>(?=[,\r\n] ))|""(?<x>([^""]|"""") )""|(?<x>[^,\r\n] )),?)",
      RegexOptions.ExplicitCapture)
              select m.Groups[1].Value).Where(i => (options == StringSplitOptions.None) || (options == StringSplitOptions.RemoveEmptyEntries && i != "")).Take(count).ToArray();
   }
}
It has four overloaded methods:
  • SplitCsv()
    All substrings are returned
  • SplitCsv(int count)
    To limit the maximum number of substrings to return
  • SplitCsv(StringSplitOptions options)
    Use StringSplitOptions.RemoveEmptyEntries to omit empty array elements from the array returned, or StringSplitOptions.None to include empty array elements in the array returned.
  • SplitCsv(int count, StringSplitOptions options)
Used like this:

string[] fields = line.SplitCsv();
string[] fields = line.SplitCsv(10);
string[] fields = line.SplitCsv(StringSplitOptions.RemoveEmptyEntries);
string[] fields = line.SplitCsv(10, StringSplitOptions.RemoveEmptyEntries);

Reading a CSV text file

It should be easy to read a CSV file as exported by Excel. But the quotes around any field that includes an embedded comma makes it trickier. I found this Regex nugget from an anonymous poster known only as 'h. brouwer'.
string[] SplitCsvLine(string line)
{
   return (from Match m in Regex.Matches(line,
   @"(((?<x>(?=[,\r\n] ))|""(?<x>([^""]|"""") )""|(?<x>[^,\r\n] )),?)",
   RegexOptions.ExplicitCapture)
           select m.Groups[1].Value).ToArray();
}

Reading a text file with TextReader

Why can't I remember the syntax for TextReader and TextWriter? They're simple enough. My only excuse is that I only use them about once a year. Or it might be because when I type
TextRead readFile = new
Intellisense abandons me.
TextReader readFile = new StreamReader(@"Book.csv");
string line;
while (true)
{
   line = readFile.ReadLine();
   if (line == null) break;
   // Process the line here
}
readFile.Close();
TextWriter writeFile = new StreamReader("Book.csv");
writeFile.WriteLine("abc");
writeFile.Close();

Wednesday, 8 February 2012

ItemsControl horizontal content layout

ItemsControl lays out its content vertically by default. To arrange it horizontally we set the Orientation of the StackPanel in the ItemsPanelTemplate. In XAML like this:
<ItemsControl>
   <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
         <StackPanel Orientation="Horizontal"/>
      </ItemsPanelTemplate>
   </ItemsControl.ItemsPanel>
</ItemsControl>
And in C#, working from the deepest levels outward, like this:
FrameworkElementFactory factoryPanel =
   new FrameworkElementFactory(typeof(StackPanel));
factoryPanel.SetValue(
   StackPanel.OrientationProperty,
   Orientation.Horizontal);

ItemsPanelTemplate template = new ItemsPanelTemplate();
template.VisualTree = factoryPanel;

ItemsControl itemsControl = new ItemsControl();
itemsControl.ItemsPanel = template;

Thursday, 2 February 2012

SortableStringValue

We have a number of different alphanumeric codes in our application that occasionally need to be sorted. Using the standard sorting mechanism we typically end up with a list that looks like this:
A1
A10
A2
A20
A3
A4

Paul has written an extension method that allows us to sort into alpha then numeric order, like this:
A1
A2
A3
A4
A10
A20

The extension method is used like this:
    var result = list.OrderBy(l => l.SortableStringValue())


public static class Extensions
{
   public static String SortableStringValue(this String text)
   {
      StringBuilder  textBuilder;
      StringBuilder  numberBuilder;
      textBuilder = new StringBuilder();
      numberBuilder = new StringBuilder();
      //Look at each char in the string
      foreach(char value in text)
      {
         switch (value)
         {
            //If its a number add it to the number builder
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
               numberBuilder.Append(value);
               break;
            //Else add it to the text builder
            default:             
               //Before we add the text, format and add any number we may have
               if (numberBuilder.Length > 0)
               {
                  textBuilder.Append(numberBuilder.ToString().PadLeft(16,'0'));
                  numberBuilder.Clear();
               }
               textBuilder.Append(value);
                  
               break;
         }
      }

      //Check to see if we have any numbers left in the builder
      if (numberBuilder.Length > 0)
      {
         textBuilder.Append(numberBuilder.ToString().PadLeft(16,'0'));
      }
      //Return the string value (The replace will allow negative number to be sorted)
      return textBuilder.ToString().Replace("-0","-00");
   }
}

Monday, 5 December 2011

RadioButton groups

A workaround from Martin for RadioButton groups.

There’s a bug in WPF (still) around RadioButton groups which doesn’t immediately manifest but will eventually seem to strike.

There’s a slightly confusing summary of issues here : http://social.msdn.microsoft.com/forums/en-US/wpf/thread/8eb8280a-19c4-4502-8260-f74633a9e2f2/

Suffice to say if you have 2 (or more) radio buttons and put them in the same group, they will reliably update each others status for a while as you’d expect. At some point (in my case I found this reliably happens after changing Document tabs a few times, or going forwards & back again in a Wizard workflow), the bindings stop working and you end up unable to check either RadioButton anymore.

I’ve messed around with various approaches – a couple are suggested in the post above.
The simplest option appears however to simply drop the GroupName=”x” from the XAML and simply do the “single-selection” logic yourself in the backing properties on your VM.

i.e. :
<RadioButton ssform:FormItem.LabelContent="{Binding Source={StaticResource ViewModel}, Path=Strings.V_Coupon, Mode=OneTime}"
                            Content="{Binding Source={StaticResource ViewModel}, Path=Strings.V_eCoupon, Mode=OneTime}"
                            IsEnabled="{Binding Source={StaticResource ViewModel}, Path=IsCouponATrigger}"
                            IsChecked="{Binding Source={StaticResource ViewModel}, Path=IsECouponATrigger, Mode=TwoWay}" />
<RadioButton Content="{Binding Source={StaticResource ViewModel}, Path=Strings.V_PrintCoupon, Mode=OneTime}"
                            IsEnabled="{Binding Source={StaticResource ViewModel}, Path=IsCouponATrigger}"
                            IsChecked="{Binding Source={StaticResource ViewModel}, Path=IsPrintedCouponATrigger, Mode=TwoWay}" />

and
public bool IsPrintedCouponATrigger
{
   get { return PromoBase.UIChoices.IsPrintedCouponATrigger; }
   set
   {
      if (value != PromoBase.UIChoices.IsPrintedCouponATrigger)
      {
         PromoBase.UIChoices.IsPrintedCouponATrigger = value;
         IsECouponATrigger = !value;
         OnPropertyChanged("IsPrintedCouponATrigger");
      }
   }
}
public bool IsECouponATrigger
{
   get { return PromoBase.UIChoices.IsECouponATrigger; }
   set
   {
      if (value != PromoBase.UIChoices.IsECouponATrigger)
      {
         PromoBase.UIChoices.IsECouponATrigger = value;
         IsPrintedCouponATrigger = !value;
         OnPropertyChanged("IsECouponATrigger");
      }
   }
}
Note the check that the value has actually changed in the setter – without this, you get into a nice infinite loop of PropertyChange notifications as each changes the other in turn!

Annoying bug, but simple enough to work around once you know about it..

Friday, 30 September 2011

SQL Output Parameter

I don't why but any SQL Parameters that are defined as outputs are not available until the SqlDataReader has been closed.
So this works:
SqlParameter reservationNumberParameter = new SqlParameter("@ReservationNumber", SqlDbType.NVarChar, 15);
reservationNumberParameter.Direction = ParameterDirection.Output;
command.Parameters.Add(reservationNumberParameter);

reader = command.ExecuteReader();

reader.Close();

reservationNumber = Convert.ToString(reservationNumberParameter.Value);

Whereas this does not work:
SqlParameter reservationNumberParameter = new SqlParameter("@ReservationNumber", SqlDbType.NVarChar, 15);
reservationNumberParameter.Direction = ParameterDirection.Output;
command.Parameters.Add(reservationNumberParameter);

reader = command.ExecuteReader();

reservationNumber = Convert.ToString(reservationNumberParameter.Value);

reader.Close();

Saturday, 12 March 2011

ResourceStrings Access Modifier

When a new Resource file is added to a project the Access Modifier defaults to Internal.

There is a small combobox at the top of the Resource editor that allows it to be changed.

Thursday, 10 March 2011

COM Data Types

Data type conversions from COM to .Net
























IDL Type.NET Type
charSystem.SByte
shortSystem.Int16
int, long, HRESULT and SCODESystem.Int32
int64System.Int64
unsigned charSystem.Byte
unsigned shortSystem.UInt16
unsigned int and unsigned longSystem.UInt32
uint64System.UInt64
floatSystem.Single
doubleSystem.Double
BSTR, LPSTR and LPWSTRSystem.String
VARIANT_BOOLSystem.Boolean
DATESystem.DateTime
GUIDSystem.Guid
DECIMALSystem.Decimal
CURRENCYSystem.Decimal
VARIANTSystem.Object
IUnknown*System.Object
IDispatch*System.Object
void*System.IntPtr
IDispatchEx*System.Runtime.InteropServices.Expando.IExpando
IEnumVariant*System.Collections.IEnumerator










COMIDL
boolean and smallchar
wchar_tunsigned short
hyper and __int64int64
[string] char*LPSTR
[string] wchar_t*LPWSTR
byteunsigned char
unsigned hyper and unsigned __int64uint64

Monday, 10 January 2011

ResourceStrings in XAML

I needed to replace some hard-coded text in the xaml templates used in our Till Roll control. There was no easy route through to a general ViewModel that could expose some relevant properties to bind to.
In the end I chose to bind directly to the ResourceStrings resource using an x:Static
...
xmlns:local="clr-namespace:Sandstorm.PointOfSale.Modules.Tender.Resources"
...
<TextBlock Padding="20,0,0,0" Text="{Binding Source={x:Static local:ResourceStrings.V_Discount}, Mode=OneTime}" FontStyle="Italic"/>

Wednesday, 8 December 2010

EditorBrowsable

The EditorBrowsableAttribute class specifies whether a property or method is viewable via Intellisense.
It is used like this:

using System.ComponentModel;
...
[EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
protected void AdvancedMethod()
{
//The property or method is a feature that only advanced users should see. An editor can either show or hide such properties
}
[EditorBrowsableAttribute(EditorBrowsableState.Always)]
protected void AlwaysMethod()
{
//The property or method is always browsable from within an editor
}
[EditorBrowsableAttribute(EditorBrowsableState.Never)]
protected void NeverMethod()
{
//The property or method is never browsable from within an editor
}
I wanted to use it with a class that provided a fluent interface to hide the common methods like Equals, GetHashCode, GetType, ToString etc. to make the fluent interface syntax cleaner.
It transpires that it is only used by Intellisense when the decorated item is in a referenced assembly - shame.
Here is the fuller explanation from Linda Lui, Microsoft Online Community Support back in June 2006:

Speaking for C#, the EditorBrowsableAttribute attribute only influences C#
IntelliSense filtering behavior if the decorated item is imported from
metadata.
That's to say, you should compile the EditorBrowsableAttribute-decorated
project(e.g project 1) into an assembly(.dll or .exe) and then in another
project(e.g project 2) add a reference to that assembly. In project 2, you
should see the attribute at work.
C# IntelliSense filtering behavior is not influenced if you are coding in
project 1. What's more, if you add a project-to-project reference to
project 1 in project 2, C# IntelliSense filtering behavior is not
influenced when you are coding in project 2 either.
The IDE is intended to filter items from consumers of your assembly and not
to filter items from yourself as you code the assembly.

Thursday, 20 August 2009

How to set a property to a DynamicResource reference in code

We recently needed to create a control in code and apply a style. The best reference I could find was this one at Josh Smith's blog: How to set a property to a DynamicResource reference in code

Our own example in XAML and C# looked like this:
<ItemsControl Style="{DynamicResource POSDatesTimesButtonItemsControlStyle}"

FrameworkElementFactory itemsControlElement = new FrameworkElementFactory(typeof(ItemsControl));
itemsControlElement.SetResourceReference(ItemsControl.StyleProperty,
"POSDatesTimesButtonItemsControlStyle");

Monday, 27 July 2009

WCF Fault Exception

Martin had an obscure problem with WCF on our Fitspace / Fitness First Widget.

This article describes a similar issue Obscure WCF Exception mislaid blame

Wednesday, 15 July 2009

Sorting Arrays

Martin pointed me at this interesting blog regarding Array.Sort Sorting Arrays

I used Array.Sort previously in this post Sorting and De-Duping Arrays but didn't investigate further at that time.

A quick look at Array.Sort(...) shows that it has 17 overloads and lots of things to try out at some point in the future.

Monday, 6 April 2009

Constructors

It became apparent the other day that I'd either forgotten some stuff about constructors or never knew it in the first place.

This web page has a good explanation of all the issues: Constructors

For example, what I hadn't really considered is that:
public class MySimpleClass
{
public MySimpleClass()
{
}
}

is converted by the compiler into:
public class MySimpleClass
{
public MySimpleClass() : base()
{
}
}
which makes a bunch of stuff easier to understand.

Similarly 'this' can be used to invoke constructors in the same class:
public class MySimpleClass : MyBaseClass
{
public MySimpleClass() : this(5)
{
}
public MySimpleClass(int x) : base(x)
{
}
}