none
SnapsToDevicePixels, how to use within ItemsControl?

    Question

  • Hi All,

    The following XAML creates a Canvas with three vertical lines with non-integer X positions. It also has an items control where the panel is a canvas and the item container style sets the Canvas.Left attached property on each Items'  ContentPresenter in order to offset the location where each item is rendered based on the ItemsControl's source binding.


    <Window x:Class="Project.Window2" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Title="Window2" xmlns:s="clr-namespace:System;assembly=mscorlib" Width="100" Height="250"
        <Window.Resources> 
            <Style TargetType="ContentPresenter" x:Key="myItem"
                <Setter Property="Canvas.Left"
                    <Setter.Value> 
                        <Binding XPath="."/> 
                    </Setter.Value> 
                </Setter> 
            </Style> 
     
            <ItemsPanelTemplate x:Key="canvasItemControl"
                <Canvas Width="100" Height="100"/> 
            </ItemsPanelTemplate> 
     
            <XmlDataProvider x:Key="ranges" XPath="Ranges"
                <x:XData> 
                    <Ranges xmlns=""
                        <Range>10.1</Range> 
                        <Range>17.6</Range> 
                        <Range>25.9</Range> 
                    </Ranges> 
                </x:XData> 
            </XmlDataProvider> 
        </Window.Resources> 
         
        <StackPanel SnapsToDevicePixels="True" Orientation="Vertical"
            <Canvas Width="100" Height="100"
                <Line X1="10.1" Y1="0" X2="10.1" Y2="100" StrokeThickness="1" Stroke="Black"/> 
                <Line X1="17.6" Y1="0" X2="17.6" Y2="100" StrokeThickness="1" Stroke="Black"/> 
                <Line X1="25.9" Y1="0" X2="25.9" Y2="100" StrokeThickness="1" Stroke="Black"/> 
            </Canvas> 
            <ItemsControl Width="100" Height="100" 
                    ItemsSource="{Binding Source={StaticResource ranges},XPath=Range}" 
                    ItemContainerStyle="{StaticResource myItem}" ItemsPanel="{StaticResource canvasItemControl}"
                <ItemsControl.ItemTemplate> 
                    <DataTemplate> 
                        <Line X1="0" X2="0" Y1="0" Y2="100" StrokeThickness="1" Stroke="Black"/> 
                    </DataTemplate> 
                </ItemsControl.ItemTemplate> 
            </ItemsControl> 
        </StackPanel> 
    </Window> 
     


    As you can see from the XML datasource, the X locations for each line withn the items control match those of the ones placed directly in the canvas above.

    If you turn the SnapsToDevicePixels off on the StackPanel you will see that the lines which are manually placed on the upper canvas align perfectly with those drawn by the ItemsControl.

    However if SnapsToDevicePixels is set to true, the lines in the upper canvas snap, but those below do not.

    From MSDN, it looks like this is the expected behaviour (http://msdn.microsoft.com/en-us/library/aa970908.aspx), I am guessing that the contents of an Items control are not run through the layout pass.

    So ... how do I solve this problem? How can I make the lines which my ItemsControl manages snap to the device pixels?

    Many thanks,
    Colin E.

    Tuesday, September 02, 2008 10:05 AM

Answers

  • I was just playing around and discovered that if you change your data template to

    <Line RenderOptions.EdgeMode="Aliased" SnapsToDevicePixels="False" X1="0" X2="0" Y1="0" Y2="100" StrokeThickness="1" Stroke="Black"/> 

    then the lines line up when the StackPaenel has SnapsToDevicePixels on (but not when it's off unless you also add RenderOptions.EdgeMode="Aliased" to the StackPanel).

    I've absolutely no idea why this works!!!

    Chris Jobson
    Tuesday, October 14, 2008 8:35 PM
  • Hi Chris,

    Many thanks for that - it works a treat :-)

    With the following code, the two sets of lines are perfectly aligned:

    <StackPanel RenderOptions.EdgeMode="Aliased" Orientation="Vertical"
            <Canvas Width="100" Height="100"
                <Line X1="10.1" Y1="0" X2="10.1" Y2="100" StrokeThickness="1" Stroke="Black"/> 
                <Line X1="17.6" Y1="0" X2="17.6" Y2="100" StrokeThickness="1" Stroke="Black"/> 
                <Line X1="25.9" Y1="0" X2="25.9" Y2="100" StrokeThickness="1" Stroke="Black"/> 
            </Canvas> 
            <ItemsControl Width="100" Height="100"  
                    ItemsSource="{Binding Source={StaticResource ranges},XPath=Range}"  
                    ItemContainerStyle="{StaticResource myItem}" ItemsPanel="{StaticResource canvasItemControl}"
                <ItemsControl.ItemTemplate> 
                    <DataTemplate> 
                        <Line   X1="0" X2="0" Y1="0" Y2="100" StrokeThickness="1" Stroke="Black"/> 
                    </DataTemplate> 
                </ItemsControl.ItemTemplate> 
            </ItemsControl> 
        </StackPanel> 

    I had no idea you could turn the anti-aliasing off.

    I will make a note of this in my article which links to this thread:
    http://www.codeproject.com/KB/WPF/WpfWinFormsBulletGraphs.aspx

    Thanks again.

    Regards, Colin E. -- Please mark any posts that answer your questions as an 'answer'
    Wednesday, October 15, 2008 7:44 AM

All replies

  • bump

    ... I am guessing the answer is simply "no, you can't do that", but it would be nice to get some confirmation.

    Colin E.
    Friday, September 26, 2008 9:15 AM
  • I was just playing around and discovered that if you change your data template to

    <Line RenderOptions.EdgeMode="Aliased" SnapsToDevicePixels="False" X1="0" X2="0" Y1="0" Y2="100" StrokeThickness="1" Stroke="Black"/> 

    then the lines line up when the StackPaenel has SnapsToDevicePixels on (but not when it's off unless you also add RenderOptions.EdgeMode="Aliased" to the StackPanel).

    I've absolutely no idea why this works!!!

    Chris Jobson
    Tuesday, October 14, 2008 8:35 PM
  • Hi Chris,

    Many thanks for that - it works a treat :-)

    With the following code, the two sets of lines are perfectly aligned:

    <StackPanel RenderOptions.EdgeMode="Aliased" Orientation="Vertical"
            <Canvas Width="100" Height="100"
                <Line X1="10.1" Y1="0" X2="10.1" Y2="100" StrokeThickness="1" Stroke="Black"/> 
                <Line X1="17.6" Y1="0" X2="17.6" Y2="100" StrokeThickness="1" Stroke="Black"/> 
                <Line X1="25.9" Y1="0" X2="25.9" Y2="100" StrokeThickness="1" Stroke="Black"/> 
            </Canvas> 
            <ItemsControl Width="100" Height="100"  
                    ItemsSource="{Binding Source={StaticResource ranges},XPath=Range}"  
                    ItemContainerStyle="{StaticResource myItem}" ItemsPanel="{StaticResource canvasItemControl}"
                <ItemsControl.ItemTemplate> 
                    <DataTemplate> 
                        <Line   X1="0" X2="0" Y1="0" Y2="100" StrokeThickness="1" Stroke="Black"/> 
                    </DataTemplate> 
                </ItemsControl.ItemTemplate> 
            </ItemsControl> 
        </StackPanel> 

    I had no idea you could turn the anti-aliasing off.

    I will make a note of this in my article which links to this thread:
    http://www.codeproject.com/KB/WPF/WpfWinFormsBulletGraphs.aspx

    Thanks again.

    Regards, Colin E. -- Please mark any posts that answer your questions as an 'answer'
    Wednesday, October 15, 2008 7:44 AM