Поделиться через


Signals for WPF in C# AND XAML!

I would like to introduce the WPF signal library on codeplex, which is my wrapper around .NET 3.5 that provides a higher level interface to dependency properties in C#. Currently, databinding in C# and XAML is verbose and painful: you have to call BindingOperations (from C#) and often write various value converters (impossible in XAML). The WPF signal library replaces this complexity with a signal construct that allows binding of a dependency property through simple expressions. Example, say you want a rectangle to always appear at the bottom of its containing canvas; with the WPF signal library, this only requires one line of code:

using SignalLib;

...

rectangle.top().bind = canvas.height() - rectangle.height();

top() and height() are respectively signal wrappers around Canvas.TopProperty and FrameworkElement.TopProperty. Extension methods make these signals accessible in Canvas and Rectangle, while operator overloading defines the minus method for double signals. The result is that the rectangle is stuck to the bottom of the canvas. Many operators can be undone, meaning it is possible to bind signal expressions that compose multiple signals; e.g.,

 (rectangle.top() + rectangle.height()).bind = canvas.height();

is equivalent to the former code. In the binding, the + operation is undone so that the rectangle's top property is bound to the canvas's height - the rectangle's height. Actually, this is how we define the bottom signal, so one can write:

 rectangle.bottom().bind = canvas.height();

We also define signals that combine dependency properties and other signal expressions into points and vectors. For example, say you want the rectangle to be half the size of the canvas; this can be accomplished with the following simple statement:

 rectangle.size().bind = canvas.size() / 2d;

Using this approach, we can provide multiple ways of setting a UI element’s position. For example, consider placing the rectangle at the center bottom of the canvas:

 rectangle.centerBottom().bind = (canvas.width() /2d).point(canvas.height());

Finally, the new release of the WPF signal library supports the embedding of signal expressions into XAML! Example:

 

 <UserControl x:Class="SignalExample.ChessExample"
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:l="clr-namespace:SignalExample"
  xmlns:s="clr-namespace:SignalLib;assembly=SignalLib">
  <Canvas Background="Gray" ClipToBounds="true">
    <Image x:Name="piece" Source="images/piece.png" 
           s:Signals.CenterPosition="{s:Signal outer.center}"/>
    <Thumb x:Name="sun" Background="Yellow" 
           s:Signals.Size="{s:Signal (10\,10) + ((0.1\,0.1) * 
             (piece.centerPosition - centerPosition).length)}" 
           s:Signals.LeftTop="{s:Signal (10\,30)}" s:Signals.MoveOption="Both"/>
    <Image x:Name="highlight" Source="images/highlight.png" 
           s:Signals.CenterTop="{s:Signal piece.centerTop}"
           s:Signals.Rotate="{s:Signal piece.centerPosition - leftTop, 
             piece.centerPosition.angle(sun.centerPosition)}"/>
  </Canvas>
</UserControl>

The s:Signals.XXXX are pseudo properties that allow us to bind the composed properties I talked about above; e.g., s:Signals.CenterBottom would allow us to bind the centerBottom signal expression. The Signal MarkupExtension is used to allow signal expressions to be expressed within XAML in a syntax that is very similar to but much more powerful than Binding. I just coded the parser for XAML and it’s still a bit buggy, but we have already found it very useful when we want more powerful data binding support in XAML without having to resort to code behind.

 

Code and release is available at codeplex: https://www.codeplex.com/wpfsignals

Comments