When DataGrid was introduced  into WPF, I was happy. I really lack this control. As many other developers I found one drawback of new control. When you use DataGridTemplateColumn, it doesn’t set focus automatically on control inside DataGridTemplateColumn.CellEditingTemplate. This requires from you to click 3 times to edit the cell or press tab twice. It is very annoying. Discussion of this bug and possible solutions was made at code plex http://www.codeplex.com/Thread/View.aspx?ProjectName=wpf&ThreadId=35540 . I found my own solution. When you start to edit cell, wpf creates controls for data edit, like textboxes. So we need to transfer focus to them immediately. I created attacher class:

public class FocusAttacher
    {

        public static readonly DependencyProperty FocusProperty = DependencyProperty.RegisterAttached("Focus", typeof(bool), typeof(FocusAttacher), new PropertyMetadata(false, FocusChanged));

        public static bool GetFocus(DependencyObject d)
        {
            return (bool)d.GetValue(FocusProperty);
        }

        public static void SetFocus(DependencyObject d, bool value)
        {
            d.SetValue(FocusProperty, value);
        }

        private static void FocusChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue)
            {
                ((UIElement)sender).Focus();
            }
        }

    }
Public Class FocusAttacher

    Public Shared ReadOnly FocusProperty As DependencyProperty = DependencyProperty.RegisterAttached("Focus", GetType(Boolean), GetType(FocusAttacher), New PropertyMetadata(False, FocusChanged))

    Public Shared Function GetFocus(ByVal d As DependencyObject) As Boolean
        Return CBool(d.GetValue(FocusProperty))
    End Function

    Public Shared Sub SetFocus(ByVal d As DependencyObject, ByVal value As Boolean)
        d.SetValue(FocusProperty, value)
    End Sub

    Private Shared Sub FocusChanged(ByVal sender As Object, ByVal e As DependencyPropertyChangedEventArgs)
        If CBool(e.NewValue) Then
            DirectCast(sender, UIElement).Focus()
        End If
    End Sub

End Class

As you can see, this class can be attached to any UIElement and calls focus immediately.
You can use it like this:

        <tk:DataGrid CanUserAddRows="True" ItemsSource="{Binding}" AutoGenerateColumns="False">
            <tk:DataGrid.Columns>
                <tk:DataGridTemplateColumn Header="Name">
                    <tk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Padding="3" Text="{Binding Name}" />
                        </DataTemplate>
                    </tk:DataGridTemplateColumn.CellTemplate>
                    <tk:DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <TextBox Text="{Binding Path=Name, Mode=OneWay}" lc:FocusAttacher.Focus="True" />
                        </DataTemplate>
                    </tk:DataGridTemplateColumn.CellEditingTemplate>
                </tk:DataGridTemplateColumn>
                <tk:DataGridTemplateColumn Header="Phone">
                    <tk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=Phone}" Padding="3"/>
                        </DataTemplate>
                    </tk:DataGridTemplateColumn.CellTemplate>
                    <tk:DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <TextBox Text="{Binding Path=Phone, Mode=OneWay}" lc:FocusAttacher.Focus="True" />
                        </DataTemplate>
                    </tk:DataGridTemplateColumn.CellEditingTemplate>
                </tk:DataGridTemplateColumn>
                <tk:DataGridTemplateColumn Header="Address">
                    <tk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=Address}" Padding="3"/>
                        </DataTemplate>
                    </tk:DataGridTemplateColumn.CellTemplate>
                    <tk:DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <TextBox Text="{Binding Path=Address, Mode=OneWay}" lc:FocusAttacher.Focus="True" />
                        </DataTemplate>
                    </tk:DataGridTemplateColumn.CellEditingTemplate>
                </tk:DataGridTemplateColumn>
            </tk:DataGrid.Columns>
        </tk:DataGrid>

This completely solves the problem, when you start to edit cell, focus immediately goes to required control.

Sample projects which show such datagrid and attacher class in action is available .

Change Property Command

February 11, 2009

Many applications requires history support (undo/redo). I found class ChangPropertyCommand very helpful for such tasks, because it allows you to specify any property of the object to be changed, so you don’t need to write many classes.

public class ChangePropertyCommand : Command
{

    private var Target_;
    private var NewValue_;
    private var OldValue_;
    private string PropertyName_;
    public ChangePropertyCommand(object Target, string PropertyName, object Value)
    {
        Target_ = Target;
        NewValue_ = Value;
        PropertyName_ = PropertyName;
        OldValue_ = GetValue();
    }

    public override void Execute()
    {
        base.Execute();
        SetValue(NewValue_);
    }

    public override void UnExecute()
    {
        base.UnExecute();
        SetValue(OldValue_);
    }

    private void SetValue(object Value)
    {
        object tmp = Target_;
        var type = Target_.GetType();
        string[] paths = PropertyName_.Split(".");
        PropertyInfo prop = type.GetProperty(paths(0));
        for (int i = 0; i <= paths.Length - 2; i++) {
            prop = type.GetProperty(paths(i));
            tmp = prop.GetValue(tmp, null);
            type = tmp.GetType;
        }
        prop = type.GetProperty(paths(paths.Length - 1));
        prop.SetValue(tmp, Value, null);
    }

    private object GetValue()
    {
        object ret = Target_;
        var type = Target_.GetType();
        string[] paths = PropertyName_.Split(".");
        foreach (string path in paths) {
            var prop = type.GetProperty(path);
            ret = prop.GetValue(ret, null);
            if (ret != null) {
                type = ret.GetType;
            }
        }
        return ret;
    }
}
Imports System.Reflection

Public Class ChangePropertyCommand
    Inherits Command

    Private Target_
    Private NewValue_
    Private OldValue_
    Private PropertyName_ As String
    Sub New(ByVal Target As Object, ByVal PropertyName As String, ByVal Value As Object)
        Target_ = Target
        NewValue_ = Value
        PropertyName_ = PropertyName
        OldValue_ = GetValue()
    End Sub

    Public Overrides Sub Execute()
        MyBase.Execute()
        SetValue(NewValue_)
    End Sub

    Public Overrides Sub UnExecute()
        MyBase.UnExecute()
        SetValue(OldValue_)
    End Sub

    Private Sub SetValue(ByVal Value As Object)
        Dim tmp As Object = Target_
        Dim type = Target_.GetType()
        Dim paths As String() = PropertyName_.Split(".")
        Dim prop As PropertyInfo = type.GetProperty(paths(0))
        For i As Integer = 0 To paths.Length - 2
            prop = type.GetProperty(paths(i))
            tmp = prop.GetValue(tmp, Nothing)
            type = tmp.GetType
        Next
        prop = type.GetProperty(paths(paths.Length - 1))
        prop.SetValue(tmp, Value, Nothing)
    End Sub

    Private Function GetValue() As Object
        Dim ret As Object = Target_
        Dim type = Target_.GetType()
        Dim paths As String() = PropertyName_.Split(".")
        For Each path As String In paths
            Dim prop = type.GetProperty(path)
            ret = prop.GetValue(ret, Nothing)
            If ret IsNot Nothing Then
                type = ret.GetType
            End If
        Next
        Return ret
    End Function

End Class

Here some example of using this class:

    ChangePropertyCommand width = new ChangePropertyCommand(CurrentElement, "Width", Current.Width);
    ChangePropertyCommand height = new ChangePropertyCommand(CurrentElement, "Height", Current.Height);
Dim width As New ChangePropertyCommand(CurrentElement, "Width", Current.Width)
Dim height As New ChangePropertyCommand(CurrentElement, "Height", Current.Height)

As you can see, this code creates two commands, they will change properties Width and Height of the CurrentElement object, by values from Current object.
Often, Execute and Unexecute methods are not called directly, but called by History class.

GreyableTextBlock

November 27, 2008

WPF naturaly doesn’t have image class, which supports Disable state. Alex P solved this problem. Label class support disable state, but TextBlock don’t. Sometimes you need to use TextBlock, not Label. So, here a little class GreyableTextBlock which addresed to this issue:

    public class GreyableTextBlock: TextBlock
    {
        static GreyableTextBlock()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(GreyableTextBlock), new FrameworkPropertyMetadata(typeof(GreyableTextBlock)));
            GreyableTextBlock.IsEnabledProperty.OverrideMetadata(typeof(GreyableTextBlock), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIsEnabledChanged)));
        }

        private Brush ForegroundBrush;
        private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GreyableTextBlock text = (GreyableTextBlock)d;
            if (e.Property.Name.Equals("IsEnabled"))
            {
                if ((e.NewValue as bool?) == false)
                {
                    text.ForegroundBrush = text.Foreground;
                    text.Foreground = Brushes.Gray;
                }
                else if ((e.NewValue as bool?) == true)
                {
                    text.Foreground = text.ForegroundBrush;
                }
            }
        }
    }

Many people find chm format very useful and use html help workshop to create chm files. But it can be not very obvious how to add flash movies. Actually chm file is archive. If you change it extension to zip and open, you will see, something like this.

Chm Structure

Chm Structure

Let’s say, you have some html page and you want to insert flash movie at it. I assume, that you will have html markup similar to this:

<object id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="498" codebase="http://active.macromedia.com/flash7/cabs/ swflash.cab#version=9,0,28,0">
   <param name="src" value="/Flash/Some.swf"/>
   <param name="bgcolor" value="#1a1a1a"/>
   <param name="quality" value="best"/>
   <param name="allowScriptAccess" value="always"/>
   <param name="allowFullScreen" value="true"/>
   <param name="scale" value="showall"/>
   <param name="flashVars" value="autostart=false"/>
   <embed name="csSWF" src="/Flash/Some.swf" width="640" height="498" bgcolor="#1a1a1a" quality="best" allowScriptAccess="always" allowFullScreen="true" scale="showall" flashVars="autostart=false" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"></embed>
</object>

But this will not work, because html help workshop will not add you flash movie (Some.swf) to chm file. You can check this using chm file as archive. It is reasonable question, why images are automatically added to chm files, but flash files are not? A suppose chm format wasn’t designed to display flash content.
So, we need to add flash content to chm file, but there is no way to specify for html help workshop which files should be added except htm files. But we know, that images, css and javascript files used in htm files are added automatically to resulted chm file. This leads to simple trick.

<img src="/Flash/Some.swf" style="visibility:hidden" />

This will enforce html workshop help to add Some.swf to resulted chm file. Html help workshop doesn’t check extension of file, so you can add any desired content. Style “visibility:hidden” prevents image from displaying. That is all! Have fun!

Color Reduction in WPF

September 27, 2008

Sometimes we need to reduce colors in image by some reasons. WPF has built-in ability to reduce colors of the image. FormatConvertedBitmap class was design to perform such operations. Let’s take a look on the following code, which is part of demo available to download:

FormatConvertedBitmap newFormatedBitmapSource = new FormatConvertedBitmap();
newFormatedBitmapSource.BeginInit();
//Set source from image control
newFormatedBitmapSource.Source = iSource.Source as BitmapSource;

//Create palette of requied color. Pay heed to maxColorCount it can have any value, but PixelFormats supports only 2,4,16 and 256 colors.
BitmapPalette myPalette = new BitmapPalette(iSource.Source as BitmapSource, int.Parse(cbNumberOfColors.SelectionBoxItem as string));

newFormatedBitmapSource.DestinationPalette = myPalette;

//Set PixelFormats
newFormatedBitmapSource.DestinationFormat = PixelFormats.Indexed8;
newFormatedBitmapSource.EndInit();

iReduced.Source = newFormatedBitmapSource;

There are two important moments here. First,

//Create palette of requied color. Pay heed to maxColorCount it can have any value, but PixelFormats supports only 2,4,16 and 256 colors.
BitmapPalette myPalette = new BitmapPalette(iSource.Source as BitmapSource, int.Parse(cbNumberOfColors.SelectionBoxItem as string));

As you can see, we create Palette from source image. In the second parameter of the constructor we passing the desired number of colors. It creates palette with desired number of colors. Sweet. How does that works? I used reflector to find out. It uses IWICPalette_InitializeFromBitmap_Proxy function from windowscodecs.dll. This function has the following remark:

“The resulting palette contains the specified number of colors which best represent the colors present in the bitmap (according to the algorithm we use). The algorithm operates on the opaque RGB color value of each pixel in the reference bitmap and hence ignores any alpha values. If a transparent color is required, set the fAddTransparentColor parameter to TRUE and one fewer optimized color will be computed and a fully transparent color entry will be added.

This method is particularly useful with the error diffusion dithering algorithm described in the format conversion section.”

They don’t specify, which algorithm is used (  Official documentation has the following hint:

“They are intended to provide the best possible image quality with a reduced set of colors. Optimal palettes are generated from an image’s pixel values – usually using a histogram.”

So, we have palette now. Next, we need to assign indexes to all pixels from palette. If you take a look on the code, you probably didn’t find line, which suppose to assign indexes to pixels. I used to reflector to find out where it happens. Method FormatConvertedBitmap.EndInit calls virtual FinalizeCreation, which calls IWICFormatConverter_Initialize_Proxy from windowscodecs.dll. This function do the trick. It assigns indexes to pixels.

At the last part, I show you screen of the demo program and will give some comments.

Color reduction sample

Color reduction sample

This demo very simple. You can load image from hard disc to the left image box and convert it to the right image box by pressing “Convert” button. Save button allows you to save result on you hd. Combobox specifies desired number of colors.

You also can download whole VS2008 project in the zip archive. Change it’s extension, it is zip not pdf.

PS If somebody knows algorithms, which is used in windowscodecs.dll, please let me know, i will appreciate this.

WPF Clipboard Viewer

April 30, 2008

One of the common tasks is to monitor clipboard and perform some actions, when it changes. I encountered such task in WPF. WPF as well as .NET doesn’t have any built in components to solve this task. After some googling i found a great article, which describes how to monitor clipboard in windows form. I am strongly recommended to read this article, because further reading assumes, that you know it.

Why this approach is not possible in WPF? Because WPF Window doesn’t have property Handle and you can’t override WndProc. Seems to be troublesome. First problem can be solved using PresentationSource class. PresentationSource  is another wrapper around windows handle. You can get it using PresentationSource.FromVisual method. Actually, you will be working with HwndSource class, which is derived from PresentationSource. HwndSource has property Handle. So, first problem is solved. What about ovveriding WndProc? I don’t know how to do it in WPF, but i suggest another approach. HwndSource has method AddHook, which allows us to receive all window messages. Thanks to these ideas we can implement Clipboard Viewer in WPF. I called my class ClipBoardViewer, it construts from any HwndSource and expose event ClipBoardTextChanged. Feel free to modify it for your needs.

ClipBoardViewer.vb

Almost any developer encounter a task, where he need to make copyright string like that: ”© 2003—2008 Somecompany”. It is obviously, that you can manually code it annually. But there is more simple solution:

© 2003 — <%= DateTime.Now.Year> Somecompany

This code will produce result like ”© 2003—xxxx Somecompany”, where xxxx is the server’s year. Make sure, that server time is ok.

Introduction
The purpose of this article is to show how to write simple chat bot using C#. Bot will simply answer on any received messages, like that:
User: Hi
Skype Bot: User said: Hi
After that you can improve logic of your bot is much as needed, for example, i wrote bot, which helps me and my friends to play D&D ;) Your bot can use web services, databases or his own logic to provide assistance to user. Skype bots have great applied area. They can be pretty useful.

Library and Documentation

If you want to build skype bot you need Skype4COM.dll. It can be downloaded from developer zone of skype. Documentation also will be helpful.

“Skype4COM is an interface which represents the Skype API as objects, with properties, commands, and events and notifications. Use Skype4COM in any ActiveX environment, such as Visual Studio or Delphi, and use familiar scripting languages, such as Visual Basic, PHP, or Javascript. Skype4Com.dll is automatically included together with Skype Extras Manager during Skype installation. If a user has unchecked Extras Manager during installation, Skype4Com library will be unavailable on that machine.” — from developer zone. Obviously, C# is well suited for working with COM libraries and GUI. Documentation has visual basic script examples, but no examples on C#.

Creating C# Project and Adding Reference

Let’s start VS2005. Create C# project as Windows Application. I called it Simple Skype Chat Bot.

Create project “simple skype chat bot”

Now, we need to include Skype4COM.dll to our project. Just right-click “References” in Solution Explorer and select option “Add Reference” in popup menu. You will see four tabs in the “Add Reference” dialog box, choose COM tab. In the listbox choose Skype4COM 1.0 Type Library. You should have it, if you have Skype Extras Manager. If you don’t have it, then download it and register using regsvr32 command.

Add Reference Skype4COM

Press Ok. Now Skype4COM.dll is included to our project. VS2005 generate Runtime Callable Wrapper using TlbImp.exe. It will imports types definitions found in COM library into equivalent .NET types. If you want know more about .NET and COM interaction read “C#.NET and COM Interop” article by Ravi Sankar. You can view generated types in object explorer, select SKYPE4COMLib.

Object Browser Skype4COM 

Attaching to the Skype
SkypeClass is the main class for working with skype, we need to create it and attach to Skype. First, create a variable of this class in you from class. I prefer to make initialization of SkypeClass object atFrom_Load event, you can choose any other suitable for you.

Subscribing to Skyep events 

As you can see, variable skype of the class SkypeClass was declared. At the SkypeChatBotForm_Load event handler we check is skype running. If not we start the skype application. After that we subscibe on two events: AttachmentStatus and MessageStatus. Change of the user status fires AttachmentStatus event handler, there we attach to skype. Run the project. You will see Skype dialog. It will ask you about our application accessing skype. Say yes.

Attaching to skype 

Answering to the received messages
Our next goal is to handle receive messages in skype_MessageStatus event handler and answer to them. There are a lot of types of messages, but we have interest only in received messages. Enum TChatMessageStatus contains all possible values, so TChatMessageStatus.cmsReceived is the proper value for received message.

Answering messages 

pMessage is instance of ChatMessage class. Through it we can get access to our chat and answer using method SendMessage. pMessage.Body contains text of the received message and pMessage.FromDisplayName contains name of the person who sent message. That’s all. You can run your bot and chat with somebody. He will be surprised of your typing speed ;-)

Chating with bot 

As you can see, Aleksey said “Hi” to me and bot answered from my account.

Deployment

If you will decide to publish your bot, you should keep in mind, that not all users have Skype4COM.dll. Maybe you need to include it in your deployment package and register in user’s systems.

Conclusion

As you noticed, bot answered to received message by my name, not something like “Answering Bot”. It is because your application can attach only to working copy of skype. One of the most pity things: there is no way to run more than one copy of skype in a single PC. That mean if you want to create useful bot, which will work always and has his own name — you need to create skype account and run this account with this bot on separate PC or virtual machine. In any way it is very resource consuming. I am dreaming about COM component which will allows to use skype network without attaching to already running GUI. Something like Skype engine library. But it seems impossible due to commercial reasons, because then anybody will have possibility to write his own Skype client.

Thanks for assistance

  • Aleksey Shmatov
  • Tanya Koltunova

Download Source Code