none
listbox中元素间距问题(不能靠右对齐)(莫名缺少两个像素) RRS feed

  • 问题

  • 1地方是一个listbox 设置listbox高度为48,结果显示出来只有46个像素点.
    2地方设置是60高.只有58.
    3,处设置为靠右结果会有几个像素点的差别.还会多个莫名其妙的滚动条,且初始化之后点击2区域的那个白色条之后,3区域左边那特细的竖条会变蓝(截不到图)且会莫名的往左滚动几个像素点,不细看很难看出来.但很显然他没有对齐.
    总体来说就是设置listbox高度之后会有莫名其妙的少两个像素点,在显示音乐符号的图标那也是,border高为50,图片高度设置为48之后,图片右边就会多个竖的滚动条.不知道listbox有没有其他设置的地方.
    附源码:(本不想贴这么多的,但是看了几遍不知道问题,怕少贴了.各位受累了)
    <UserControl x:Class="Xinshubiao.Views.PlayItemCollectionListView"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:cm="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
                xmlns:vm="clr-namespace:Xinshubiao.ViewModels"
                        xmlns:local="clr-namespace:Xinshubiao.Views"
                 xmlns:model="clr-namespace:Xinshubiao.Models"
                 mc:Ignorable="d" 
    
                 d:DesignHeight="300" d:DesignWidth="300">
        <UserControl.Resources>
            <Style x:Key="nullListbox" TargetType="{x:Type ListBox}"></Style>
    
            <model:DurationToPixelConverter x:Key="durationToPixel" />
            <Style x:Key="nullStyle" TargetType="{x:Type ScrollViewer}"></Style>
            <!-- ItemContainerStyle with the Trigger for Selected -->
            <Style x:Key="RedGlowItemContainer" TargetType="{x:Type ListBoxItem}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListBoxItem}">
                            <Canvas x:Name="Screen" AllowDrop="False"  ScrollViewer.HorizontalScrollBarVisibility="Hidden" HorizontalAlignment="Left"
                                    >
                                <Border BorderThickness="1" BorderBrush="Yellow" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                        		x:Name="IconBorder" Visibility="Collapsed" Canvas.Left="{Binding StartDuration, Converter={StaticResource durationToPixel}}">
                                    <local:ThumbnailItemView  Canvas.Left="{Binding StartDuration, Converter={StaticResource durationToPixel}}"
                                                              ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                        cm:Message.Attach="[Event MouseLeftButtonDown] = [Action Label_MouseLeftButtonDown($source, $eventArgs)];
                            [Event MouseMove] = [Action Label_MouseMove($source, $eventArgs)];
                            [Event MouseLeftButtonUp] = [Action Label_MouseLeftButtonUp($source, $eventArgs)]"  
                                              />
                                </Border>
                            </Canvas>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsSelected" Value="true">
                                    <Setter TargetName="IconBorder"  Property="Visibility" Value="Visible">
                                    </Setter>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
    
            <ItemsPanelTemplate x:Key="playItemCollectionPanelTemplate">
                <Grid  Height="50" />
            </ItemsPanelTemplate>
    
            <ItemsPanelTemplate x:Key="listboxitemsPanelTemplate">
                <Canvas  Background="GhostWhite" Margin="0"
                    cm:Action.TargetWithoutContext="{Binding}"  AllowDrop="True"
                        cm:Message.Attach="[Event Drop]=[Action AddThumbnailItem($source, $eventArgs)];
                                                                [Event MouseMove]=[Action Canvas_MouseMove($source, $eventArgs)]"/>
            </ItemsPanelTemplate>
    
            <DataTemplate x:Key="listboxPlayItemDataTemplate">
                <Canvas x:Name="Screen" AllowDrop="False"  ScrollViewer.HorizontalScrollBarVisibility="Hidden" HorizontalAlignment="Left">
                    <local:ThumbnailItemView  Canvas.Left="{Binding StartDuration, Converter={StaticResource durationToPixel}}" 
                        cm:Message.Attach="[Event MouseLeftButtonDown] = [Action Label_MouseLeftButtonDown($source, $eventArgs)];
                            [Event MouseMove] = [Action Label_MouseMove($source, $eventArgs)];
                            [Event MouseLeftButtonUp] = [Action Label_MouseLeftButtonUp($source, $eventArgs)]"  
                                              />
                </Canvas>
            </DataTemplate>
            <DataTemplate x:Key="listboxPlayItemCollectionDataTemplate">
                <ListBox  Height="60" Width="{Binding Source={x:Static vm:PlayItemCollectionListViewModel.Instance}, Path=TotalWidth}" Canvas.Left="0"
                         BorderThickness="0" ScrollViewer.CanContentScroll="False" Margin="0" Style="{DynamicResource nullListbox}"
                          HorizontalAlignment="Left"
                    ItemsPanel="{DynamicResource listboxitemsPanelTemplate}"
                    SelectedItem="{Binding SelectedThumbnailItem}"
                    ItemsSource="{Binding ThumbnailItemList}"
                          ItemContainerStyle="{DynamicResource RedGlowItemContainer}"
                    cm:Message.Attach="[Event SelectionChanged] = [Action Label_SelectionChanged($source, $eventArgs)]">
                </ListBox>
            </DataTemplate>
        </UserControl.Resources>
    
        <ListBox x:Name="lbVertical"   BorderThickness="0" Background="Transparent"  ScrollViewer.CanContentScroll="False" Padding="0"
                 HorizontalAlignment="Left" HorizontalContentAlignment="Left"
                 ItemsSource="{Binding ThumbnailItemCollectionList}" Style="{DynamicResource nullListbox}"
                 ItemTemplate="{DynamicResource listboxPlayItemCollectionDataTemplate}"
                 SelectedItem="{Binding SelectedThumbnailItemCollection}"
                 cm:Message.Attach="[Event SelectionChanged] = [Action HandleSelectionChanged($source, $eventArgs)];
                                                         [Event MouseMove] = [Action HandleMouseMove($source, $eventArgs)]"
                 />
    </UserControl>
    
    
    谢谢
    2011年11月17日 12:28

答案

  • 不是莫名其妙,是本身这个控件里面就有2个或者几个像素的边距,这个是硬编码在控件样式里面的。举个例子,WPF中的TextBox在不同的主题下,也有内部硬编码的边距的,http://social.msdn.microsoft.com/Forums/ar/wpf/thread/c540a79d-d136-4518-88c1-c8a4019b27ef

    而ListBox的硬编码边距,你在ListBox的默认样式里面可以看见:

     

        <ControlTemplate TargetType="ListBox">
          <Border Background="{TemplateBinding Control.Background}" BorderBrush="{TemplateBinding Control.BorderBrush}" BorderThickness="{TemplateBinding Control.BorderThickness}" Name="Bd" Padding="1" SnapsToDevicePixels="True">
            <ScrollViewer Focusable="False" Padding="{TemplateBinding Control.Padding}">
              <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
            </ScrollViewer>
          </Border>
          ......
    

    假如我们把Border的内边距设置为0,就看不见那左右上下各一个像素的差距了:
      <Window.Resources>
        <ControlTemplate x:Key="Template1" TargetType="ListBox">
          <Border Background="{TemplateBinding Control.Background}" 
                  BorderBrush="{TemplateBinding Control.BorderBrush}" 
                  BorderThickness="{TemplateBinding Control.BorderThickness}" 
                  Name="Bd" 
                  Padding="0" 
                  SnapsToDevicePixels="True">
            <ScrollViewer Focusable="False" Padding="{TemplateBinding Control.Padding}">
              <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
            </ScrollViewer>
          </Border>
          <ControlTemplate.Triggers>
            <Trigger Property="UIElement.IsEnabled" Value="False">
              <Setter Property="Border.Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
            </Trigger>
            <Trigger Property="ItemsControl.IsGrouping" Value="True">
              <Setter Property="ScrollViewer.CanContentScroll" Value="False" />
            </Trigger>
          </ControlTemplate.Triggers>
        </ControlTemplate>
      </Window.Resources>
      <Grid>
        <ListBox Height="50" Template="{StaticResource Template1}" HorizontalContentAlignment="Right">
          <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
              <StackPanel Orientation="Horizontal" HorizontalAlignment="Right"/>
            </ItemsPanelTemplate>
          </ListBox.ItemsPanel>
          <ListBoxItem Background="Red">Item1</ListBoxItem>
          <ListBoxItem Background="Blue">Item2</ListBoxItem>
        </ListBox>
      </Grid>
    

     

    PS.我的代码演示了如何在ListBox里面实现Item右对齐排列,并不是用Canvas和设置右边距,只要StackPanel就可以了。


    Sincerely,

     

     


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    2011年11月18日 5:37
    版主

全部回复

  • 不是莫名其妙,是本身这个控件里面就有2个或者几个像素的边距,这个是硬编码在控件样式里面的。举个例子,WPF中的TextBox在不同的主题下,也有内部硬编码的边距的,http://social.msdn.microsoft.com/Forums/ar/wpf/thread/c540a79d-d136-4518-88c1-c8a4019b27ef

    而ListBox的硬编码边距,你在ListBox的默认样式里面可以看见:

     

        <ControlTemplate TargetType="ListBox">
          <Border Background="{TemplateBinding Control.Background}" BorderBrush="{TemplateBinding Control.BorderBrush}" BorderThickness="{TemplateBinding Control.BorderThickness}" Name="Bd" Padding="1" SnapsToDevicePixels="True">
            <ScrollViewer Focusable="False" Padding="{TemplateBinding Control.Padding}">
              <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
            </ScrollViewer>
          </Border>
          ......
    

    假如我们把Border的内边距设置为0,就看不见那左右上下各一个像素的差距了:
      <Window.Resources>
        <ControlTemplate x:Key="Template1" TargetType="ListBox">
          <Border Background="{TemplateBinding Control.Background}" 
                  BorderBrush="{TemplateBinding Control.BorderBrush}" 
                  BorderThickness="{TemplateBinding Control.BorderThickness}" 
                  Name="Bd" 
                  Padding="0" 
                  SnapsToDevicePixels="True">
            <ScrollViewer Focusable="False" Padding="{TemplateBinding Control.Padding}">
              <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
            </ScrollViewer>
          </Border>
          <ControlTemplate.Triggers>
            <Trigger Property="UIElement.IsEnabled" Value="False">
              <Setter Property="Border.Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
            </Trigger>
            <Trigger Property="ItemsControl.IsGrouping" Value="True">
              <Setter Property="ScrollViewer.CanContentScroll" Value="False" />
            </Trigger>
          </ControlTemplate.Triggers>
        </ControlTemplate>
      </Window.Resources>
      <Grid>
        <ListBox Height="50" Template="{StaticResource Template1}" HorizontalContentAlignment="Right">
          <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
              <StackPanel Orientation="Horizontal" HorizontalAlignment="Right"/>
            </ItemsPanelTemplate>
          </ListBox.ItemsPanel>
          <ListBoxItem Background="Red">Item1</ListBoxItem>
          <ListBoxItem Background="Blue">Item2</ListBoxItem>
        </ListBox>
      </Grid>
    

     

    PS.我的代码演示了如何在ListBox里面实现Item右对齐排列,并不是用Canvas和设置右边距,只要StackPanel就可以了。


    Sincerely,

     

     


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    2011年11月18日 5:37
    版主
  • 这两天比较累,明天到公司试试.谢谢
    2011年11月20日 12:18
  • 这个其实用canvas 是因为要做个时间轴的...可以把里面的对象拖到任何位置的....
    2011年11月21日 1:35
  • 原来如此,不过只要我们把模板里面的Border上的边线弄成0,大部分的这种边距问题都可以解决,就怕控件本身通过 C#代码硬编码设置了边距,无法通过模板样式来覆盖掉。至于排列,时间轴的话,确实Canvas要好一点。


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    2011年11月21日 10:02
    版主