Sunday 22 November 2009

Way of Binding: Linking scrolling

I had to do something to link two scrollviewers together. The use case for this is when you what to compare two things together (like diffing of objects).

To handle this the trick was to have a converter which multiplied -1 to the scrollers.


<ScrollViewer Grid.Column="0" Grid.Row="3" x:Name="leftScroller"
ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" >
<ContentPresenter Content="{Binding SelectedMarketDataOne}"
ContentTemplateSelector="{StaticResource MarketDataTemplateSelector}">
<ContentPresenter.Style>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="RenderTransform">
<Setter.Value>
<TransformGroup>
<TranslateTransform X="{Binding ElementName=rightScroller, Path=HorizontalOffset, Converter={StaticResource MultiplyConverter}, ConverterParameter=-1}" />
<TranslateTransform Y="{Binding ElementName=rightScroller, Path=VerticalOffset, Converter={StaticResource MultiplyConverter}, ConverterParameter=-1}" />
</TransformGroup>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=tbLink,Path=IsChecked}" Value="True">
<Setter Property="RenderTransform">
<Setter.Value>
<TransformGroup>
<TranslateTransform X="{Binding ElementName=rightScroller, Path=HorizontalOffset, Converter={StaticResource MultiplyConverter}, ConverterParameter=0}" />
<TranslateTransform Y="{Binding ElementName=rightScroller, Path=VerticalOffset, Converter={StaticResource MultiplyConverter}, ConverterParameter=0}" />
</TransformGroup>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentPresenter.Style>
</ContentPresenter>
</ScrollViewer>

<ScrollViewer Grid.Column="2" Grid.Row="3" x:Name="rightScroller"
ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" >
<ContentPresenter Content="{Binding SelectedMarketDataTwo}"
ContentTemplateSelector="{StaticResource MarketDataTemplateSelector}">
<ContentPresenter.Style>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="RenderTransform">
<Setter.Value>
<TransformGroup>
<TranslateTransform X="{Binding ElementName=leftScroller, Path=HorizontalOffset, Converter={StaticResource MultiplyConverter}, ConverterParameter=-1}" />
<TranslateTransform Y="{Binding ElementName=leftScroller, Path=VerticalOffset, Converter={StaticResource MultiplyConverter}, ConverterParameter=-1}" />
</TransformGroup>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=tbLink,Path=IsChecked}" Value="True">
<Setter Property="RenderTransform">
<Setter.Value>
<TransformGroup>
<TranslateTransform X="{Binding ElementName=leftScroller, Path=HorizontalOffset, Converter={StaticResource MultiplyConverter}, ConverterParameter=0}" />
<TranslateTransform Y="{Binding ElementName=leftScroller, Path=VerticalOffset, Converter={StaticResource MultiplyConverter}, ConverterParameter=0}" />
</TransformGroup>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentPresenter.Style>
</ContentPresenter>
</ScrollViewer>


Displaying Text with XAML

When displaying text in XAML you have a choice between TextBox, TextBlock and Label.  You may remember TextBox and Label from the world of WinForms.  But what's the deal with a TextBlock?  Why should I used that instead of a Label.

A label is basically a textblock with a border. So if all you want to display is a text, then probably it is best to use a TextBlock.

Proof is in the template of the Label itself, see below

<Style x:Key="LabelStyle1" TargetType="{x:Type Label}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Border SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>


Keybinding and MVVM

I had an issue where I was trying to bind key inputs and commands in my XAML.  The exception that I got was this here, "A 'Binding' cannot be set on the 'Command' property of type 'KeyBinding'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject"

The solution can be found here
http://joyfulwpf.blogspot.com/2009/05/mvvm-commandreference-and-keybinding.html

Adding a Trace Appender

Sometimes you want to see the log statements to come to your output console in addition to your log file.

<appender name="TraceAppender" type="log4net.Appender.TraceAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>


Diff Directories with ClearCase

I am not a huge fan of using ClearCase as my source control management system.  But when you work at the client site you may not have choice of that.  Here is a script to diff directories via the command line.

cleartool ls -view -recurse | grep -i -v "\\bin" | grep -i -v "\\obj"


Getting a Logger with C# and Log4Net

I use log4net at work all the time. When I first started using it years ago, I got a reference to the logger by passing in my class name. But if you have to refactor code, you may forget to change the name that you used for your logger. This can cause trouble later while debugging. Below is a simple way to get a logger.

private static readonly ILog log = LogManager.GetLogger(
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);


Listview Binding to Context Menu

I ran into an issue at work where I had to implement custom commands on a context menu on a listview.  At first I thought I could easily bind the command parameter to my selected item in the list but it was not as simple as that.

To bind to an item of a listview, you have to use RelativeSource in your binding.  Below is an example of it being used.

<ListView ItemsSource="{Binding DataItems}">     <ListView.ContextMenu>

        <ContextMenu>
            <MenuItem Header="Add"
                      Command="{Binding CustomAddCommand}"/>            
            <MenuItem Header="Delete"
                    Command="{Binding CustomDeleteCommand}"                       CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}"/>
        </ContextMenu>     </ListView.ContextMenu>                                           
</ListView>

If you would want to set a list of selected items instead of just one item use the following in your binding for the command parameter.

CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItems}"


This technique works for anything that needs a context menu.