Monday, November 10, 2008

Auto scroll ListBox in WPF

In WinForms era it was very simple to autoscroll listbox content in order to select last or newly added item. It become a bit complicated in WPF. However, complicated does not mean impossible.

image

As for me, Microsoft should add this feature to base ListBox implementation as another attempt to be attractive environment for LOB application. See, for example this thread from MSDN forums. I'm really understand this guy. He do not want to implement it with a lot of code, he just want it to be included in core WPF control (but he should mark answers)

Generally, the simplest way to it is by using attached properties. So, your code will look like this

<ListBox Height="200" l:SelectorExtenders.IsAutoscroll="true" IsSynchronizedWithCurrentItem="True" Name="list"/>

But what's going on under the hoods? There it bit complicated :) First of all, we should create attached property, named IsAutoscroll

public class SelectorExtenders : DependencyObject {

        public static bool GetIsAutoscroll(DependencyObject obj) {
            return (bool)obj.GetValue(IsAutoscrollProperty);
        }

        public static void SetIsAutoscroll(DependencyObject obj, bool value) {
            obj.SetValue(IsAutoscrollProperty, value);
        }

        public static readonly DependencyProperty IsAutoscrollProperty =
            DependencyProperty.RegisterAttached("IsAutoscroll", typeof(bool), typeof(SelectorExtenders), new UIPropertyMetadata(default(bool),OnIsAutoscrollChanged));

now handle it when you set it's value by handling new items arrivals, set current and then scroll into it

public static void OnIsAutoscrollChanged(DependencyObject s, DependencyPropertyChangedEventArgs e) {
            var val = (bool)e.NewValue;
            var lb = s as ListBox;
            var ic = lb.Items;
            var data = ic.SourceCollection as INotifyCollectionChanged;

            var autoscroller = new System.Collections.Specialized.NotifyCollectionChangedEventHandler(
                (s1, e1) => {
                    object selectedItem = default(object);
                    switch (e1.Action) {
                        case NotifyCollectionChangedAction.Add:
                        case NotifyCollectionChangedAction.Move: selectedItem = e1.NewItems[e1.NewItems.Count - 1]; break;
                        case NotifyCollectionChangedAction.Remove: if (ic.Count < e1.OldStartingIndex) { selectedItem = ic[e1.OldStartingIndex - 1]; } else if (ic.Count > 0) selectedItem = ic[0]; break;
                        case NotifyCollectionChangedAction.Reset: if (ic.Count > 0) selectedItem = ic[0]; break;
                    }

                    if (selectedItem != default(object)) {
                        ic.MoveCurrentTo(selectedItem);
                        lb.ScrollIntoView(selectedItem);
                    }
                });

            if (val) data.CollectionChanged += autoscroller; 
            else  data.CollectionChanged -= autoscroller;

        }

That's all. Also it can be done by visual tree querying (as thread started proposed). Find scrollviewer inside the ListBox visual tree and then invoke "ScrollToEnd" method of it.

Have a nice day and be good people. And, yes, WPF development team should consider this feature implemented internally for any Selector and ScrollViewer control

Source code for this article

Sunday, November 09, 2008

Programming for Windows 7

Well, Windows 7 is going to be released by the end of next year. This is great news, because it seemed, that Microsoft finally understand how to get the best of Windows Vista and make it to work not only on monster machines.

image

It even works on new brandy my wife's pinky machine. And if it works there and my wife is happy with it, this OS going to be very impressive.

image

But from the other hand, we, as developers should be ready today to developer Windows 7 ready application (by the way, Vista Battery Saver works for Windows 7 as well as for Windows Vista, in spite of the fact, that power management in Windows 7 was improved dramatically). So let's start!

First thing we need is to read big Windows 7 Developer Guide. This document will explain most of new features for developers to build applications right. What is includes?

Windows Driver Kit (WDK) 3.0

Basically, Windows 7 works with Vista drivers, however, hibernation, power management, networking, PREfast will work much better. You also will have new WMI access for reliability monitors and ACPI.

Management and deployment

By default Windows 7 uses PowerShell 2.0 and Windows Installer. For PowerShell it includes enhanced cmdlets to manage Active Directory, IIS, etc. For Windows Installer, you finally can build "chainers" by yourself (the same approach, used for latest deployment of Microsoft products such as Silverlight, Visual Studio 2008 SP1 etc.) Also, you can get advantage by using Windows Filtering Platform (Firewall) and User Account Control (UAC) from inside your application by using new APIs.

Performance

The most significant change in Windows 7 for end-user point of view is improved performance. Windows 7 kernel is much smaller, that kernel of Windows Vista. Also it uses specific patterns to decrease background activities on low power, based on system triggers. New user-mode and kernel-mode APIs are used by Windows Drivers Foundation much more efficiently. Also system services are much smarter. For example, DCIA starts only when you connect new hardware. After drivers were installed the service shuts down. The same approach used by domain join, GP changes, new IP fetching etc. Windows 7 knows to run and stop services, based on system events, which decreases average work load and enhances whole system performance.

Multi-touch gestures and Interia API and used interface in general

Yes, you can use this API for your applications. Finally we can have more, then just mouse. And it is not only about multiple mouse devices. We can use single finder panning, raw touch input data, internal multitouch ink recognition, which is also supports math. Also it uses build-in MathML export feature.

There are a lot of other enhancements, such as smart bars, windows' stacking, gadget desktop (it does not eat battery as external process anymore), system ribbon menu integration. etc

Graphics

Direct 11, new Direct2D, DirectWrite (we can turn text anti-aliasing for small fonts, hurrah!), improved WIC, DX/GDI interoperability on system level with automatic fallback for weak hardware (yes, you should not be worry about it anymore). Also new video and audio format support with human readable interfaces. Yes, no more DirectDraw hacks. We can use new high level interfaces such as MFPlay to manage playbacks, Source Reader for decoding, Sink Writer for transcoders and re-coding compressions.

Web and communication

WCF is inside, as well as distributed routing table for peer-to-peer operations. BranchCache - new technology to reduce WAN traffic and latency.

Also Windows 7 is compatible with OpenSearch (I told, that Microsoft does not know to build search engines). Sharepoint integration and environment sensors platform, that can be used either for desktop and web applications.

There are much more features, that makes Windows 7 to pretend to be very good operation system. If you want to learn more about all those Windows 7 new features, I highly advice you to download and read this document. It includes most of new features of new OS with explanations and screenshots to make your learn and understand what can your future application do with all those new features.

Have a nice day and be good people.

BTW, if you have PDC version of Windows 7 and want to unlock it for using of some cool features, introduced during keynotes, it worth to visit here and learn how to :)

Download Windows 7 Developer Guide and start programming.

Monday, October 20, 2008

P/Invoke cheat sheet

I’m working a lot with p/invoke, and know how it’s hard to produce correct signature for unmanaged method. So, today I decided to publish basic cheat sheet for methods, parameters and attributes you should use in order to invoke unmanaged methods from managed code without a lot of problems. We start with data type translations. Here the table to understand it.

Data type from unmanaged signature Data type in managed signature
int int

the same with all other simple types such as double, uint, etc or private objects
void* IntPtr
int* ref int

the same with all other simple types such as double, uint, etc or private objects
char** ref IntPtr

later, you should get ascii string by using System.Runtime.InteropServices.Marshal.PtrToStringAnsi() method
wcar_t** ref IntPtr

later, you should get ascii string by using System.Runtime.InteropServices.Marshal.PtrToStringUni() method
const int* ref int
const char* [System.Runtime.InteropServices.In()] [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string
(variable argument) [System.Runtime.InteropServices.In()] [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.AsAny)] object

You can use either System.Runtime.InteropServices.In or System.Runtime.InteropServices.Out attribute to specify how arguments should be used.

Now we done with simple arguments, let’s see what can be done when argument is actually callback or delegate?

Unmanaged definition Managed definition
typedef void (*MyCallback)(int Arg)

[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]delegate void MyCallback(int Arg)
Caller cleans stack argument is used to assure, that we can call varargs type function, usually used by API provider. It is very similar to C# overrides for methods. Also you can use StdCall (this is default), ThisCall – stores this first and pushes other parameters on the stack, FastCall – not very supported :(

 

To call all those methods, we should know managed equivalents of unmanaged types. Here the table. The rule is simple – know how many bytes unmanaged type has and find managed type with the same number of bytes. Other words, you can marshal int into IntPtr too…

Unmanaged type Managed equivalent
bool bool
char sbyte (signed), byte (unsigned)
wchar_t char
double double
float single
int, long (signed) Int32
int, long (unsigned) UInt32
__int64 (signed) Int64
__int64 UInt64
short (signed) Int16
short (unsigned) UInt16
void void

But not only types are problem in managed/unmanaged transitions. Also structures are aligned differently. For this purpose we can use StructLayout attribute. Even if unmanaged classes are sequential and you used correct managed data types, you can find you with problems in Pack. What “pack” is? Pack is actually slot size in bytes for members of your structure. It can be 0, 1, 2, 4, 8, 16, 32, 64, or 128 and depends on the platform and application setting.

Now you can see, that it is not very complicated to create managed signatures when you have header of unmanaged assemblies. So go ahead and ask, if I missed something.

That’s all by now. Have a nice day and be good people.

Monday, October 13, 2008

Set binding, based on trigger

Let’s say, that you want to set binding. However, you want to set it by using some trigger. Wait! Why I need it? Let’s say, that I have some very special object, that actually has no hard-coded properties. All it’s properties are created during the runtime, based on some trigger. In this case, I still want to use binding, however, if the property does not exists, I cannot do it. In this special case (that we’ll probably speak more later), we can use this class – TriggerBinding.

How to do it? How to extend build-in binding and add such functionality? Simple. All we need is to write custom markup extension. So, we’ll create new one

public class TriggerBindingExtension : MarkupExtension

And expose all regular binding properties + three custom – TriggerSource, TriggerSourceName and Trigger itself

public IValueConverter Converter { get; set; }
public object ConverterParameter { get; set; }
public string ElementName { get; set; }
public RelativeSource RelativeSource { get; set; }
public object Source { get; set; }
public string TriggerSourceName { get; set; }
public UIElement TriggerSource { get; set; }
[TypeConverter(typeof(RoutedEventConverter))]
public RoutedEvent Trigger { get; set; }
public bool ValidatesOnDataErrors { get; set; }
public bool ValidatesOnExceptions { get; set; }
public string StringFormat { get; set; }
[TypeConverter(typeof(EnumConverter))]
public BindingMode Mode { get; set; }
[TypeConverter(typeof(PropertyPathConverter))]
public PropertyPath Path { get; set; }
[TypeConverter(typeof(BooleanConverter))]
public bool IsAsync { get; set; }
public string XPath { get; set; }
[TypeConverter(typeof(CultureInfoIetfLanguageTagConverter))]
public CultureInfo ConverterCulture { get; set; }

Next step is to override ProvideValue method of MarkupExtension and create the actual binding. We still do not want to bind it to any property

public override sealed object ProvideValue(IServiceProvider serviceProvider) {
        var _valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
        if (_valueProvider != null) {
           var _bindingTarget = _valueProvider.TargetObject as FrameworkElement;
           var _bindingProperty = _valueProvider.TargetProperty as DependencyProperty;
           var _binding = new Binding();
           _binding.Path = Path;
           _binding.XPath = XPath;
           _binding.Mode = Mode;
           _binding.Converter = Converter;
           _binding.ConverterCulture = ConverterCulture;
           _binding.ConverterParameter = ConverterParameter;
           _binding.IsAsync = IsAsync;
           if (ElementName != null) _binding.ElementName = ElementName;
           if (RelativeSource != null) _binding.RelativeSource = RelativeSource;
           if (Source != null) _binding.Source = Source;
           _binding.ValidatesOnDataErrors = ValidatesOnDataErrors;
           _binding.ValidatesOnExceptions = ValidatesOnExceptions;
           _binding.StringFormat = StringFormat;

Now, if we have TriggerSource and Trigger, everything fine, we can set subscribe to the trigger event and wire binding in the handler

private RoutedEventHandler _bindigHandler;

private void _registerHandler(FrameworkElement bindingTarget, DependencyProperty bindingProperty, Binding binding) {
   if (_bindigHandler == default(RoutedEventHandler)) {
      _bindigHandler = (RoutedEventHandler)(delegate {
         var _oldValue = bindingTarget.GetValue(bindingProperty);
         bindingTarget.SetBinding(bindingProperty, binding);
         if (_oldValue != bindingProperty.DefaultMetadata.DefaultValue) {
            bindingTarget.SetValue(bindingProperty, _oldValue);
            BindingOperations.GetBindingExpression(bindingTarget, bindingProperty).UpdateSource();
         }
      });
      TriggerSource = TriggerSource ?? bindingTarget;
      if (Trigger != null && TriggerSource != null) {
         TriggerSource.AddHandler(Trigger, _bindigHandler);
      } else {
         _bindigHandler.Invoke(this, null);
      }
   }
}

However, we also want to be able to seek Logical tree and find trigger source by it’s name. Let’s say this way

<TextBox Name="one" Text="{l:TriggerBinding ElementName=two, Path=Text, Mode=TwoWay, TriggerSourceName=three, Trigger=Button.Click}"/>
<TextBox Name="two"/>
<Button Name="three" Content="Click to trigger binding"/>

What’s the problem? We also have FrameworkElement.FindName method and LogicalTreeHelper.FindLogicalNode. But wait, in our case, when TextBox “one” is initialized, we still have no Button “three”, so we have to wait until the root element of TextBox will be fully loaded and then try to find logical node. For this purpose, we have very useful extended method

public static DependencyObject GetRoot(this DependencyObject current) {
         var _root = current;
         do { _root = LogicalTreeHelper.GetParent(_root); if (_root != null) current = _root; } while (_root != null);
         return current;
      }

So, all we have to do is to subscribe to Loaded event of the root and then wire the trigger for set binding

if (!string.IsNullOrEmpty(TriggerSourceName)) {
   var _root = _bindingTarget.GetRoot() as FrameworkElement;
   _root.Loaded += delegate {
      TriggerSource = LogicalTreeHelper.FindLogicalNode(_root, TriggerSourceName) as UIElement;
      _registerHandler(_bindingTarget, _bindingProperty, _binding);
   };
} else { _registerHandler(_bindingTarget, _bindingProperty, _binding); }

We done. Have a good day and be good people.

BTW, it’s also possible to postpone binding by using timer. Paul Stovell has very good sample of how to perform it.

Source code for this article

Saturday, October 11, 2008

Issues, you reported were fixed

Hi, folks. And thank you for reporting issues with WpfPerf Performance Profiling tool. Now it was fixed, so, download and use new and fixed version.

Keep reporting, as you can see, you have the power to change!

image

Imaginary by Malcolm Dare

Sunday, October 05, 2008

Silverlight Bidi Controls Library RC0 and movement from Beta 2 to RC0

Finally, I got free minute to convert Silverlight BiDi controls from Silverlight beta 2 to RC0 (you can download SL rc0 tools for VS2008 here) and as usual some breaking changes (the full list is here)

  • Calendar and DatePicker moved from System.Windows.Controls.Extended into System.Windows.Controls – Extended namespace is now deprecated.
  • CalendarButton is not inside System.Windows.Controls.Primitives
  • TypeConverter.CanConvertFrom(Type sourceType) was changed and now it has new first parameter ITypeDescriptorContext context
  • TypeConverter.CanConvertFrom(object value) was changed and now it has new first parameter ITypeDescriptorContext context and second parameter System.Globalization.CultureInfo culture
  • TypeConverter.ConvertFromString is not virtual anymore
  • TextDecorationCollectionConverter was removed
  • generic.xaml should be placed into themes directory (as in WPF)
  • VisualTransition.Duration is not VisualTransition.GeneratedDuration
  • ContentPresenter has no HorizontalContentAlignment and VerticalContentAlignment. It has HorizontalAlignment and VerticalAlignment now. Also it has no Background, Padding,TextAlignment,TextDecorations and TextWrapping properties

Those, basically, all changes done in Silverlight RTL support library. So, you can download and use the latest version within Silverlight RC0 version

Have a nice day and be good people.

Saturday, October 04, 2008

Free Microsoft Expression series video training catalogs

MSDN download center just published video catalogs, where you can find sample chapters of Total Training’s video series for Microsoft Expression studio. Worth to download and see. Here the breakdown by products

Also, if you are “in” Office development, it makes sense to take a look in to Data Connectivity Components for Office 2007 System. It can be used by non-Microsoft Office applications to read data from Office system files.

Happy downloading!