2013-01-23 39 views
0

在我的WPF应用程序中,我已经重新设计了ComboBox。问题是我似乎无法正确应用BorderThickness。我认为我做得正确,但我必须错过一些东西,因为结果不是我所期望的(它始终保持为1的厚度)。TemplateBinding没有传递正确的值

组合框如在用户控件使用(注意3的厚度):

<ComboBox DockPanel.Dock="Top" SelectedItem="{Binding CurrentAnalysisKey}" 
      ItemsSource="{Binding AnalysisKeys}" Height="25" 
      BorderBrush="{StaticResource ListBoxBorderBrush}" 
      BorderThickness="3" 
      DisplayMemberPath="ReaffectedName" Margin="0,5" /> 

如在资源文件中定义的组合框风格:

<Style TargetType="{x:Type ComboBox}"> 
    <Setter Property="Foreground" 
      Value="White" /> 
    <Setter Property="SnapsToDevicePixels" 
      Value="true" /> 
    <Setter Property="BorderBrush" 
      Value="{StaticResource BlackBorderBrush}" /> 
    <Setter Property="BorderThickness" 
      Value="2" /> 
    <Setter Property="Template" 
      Value="{DynamicResource ComboBoxTemplate}" /> 
</Style> 

<Style d:IsControlPart="True" 
     TargetType="{x:Type ComboBoxItem}"> 
    <Setter Property="Foreground" 
      Value="White" /> 
    <Setter Property="SnapsToDevicePixels" 
      Value="true" /> 
    <Setter Property="Template"> 
    <Setter.Value> 
     <ControlTemplate TargetType="{x:Type ComboBoxItem}"> 
     <ControlTemplate.Resources> 
      <Storyboard x:Key="HoverOn"> 

      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
              Storyboard.TargetName="HoverRectangle" 
              Storyboard.TargetProperty="(UIElement.Opacity)"> 
       <SplineDoubleKeyFrame KeyTime="00:00:00.1000000" 
            Value="1" /> 
      </DoubleAnimationUsingKeyFrames> 

      </Storyboard> 
      <Storyboard x:Key="HoverOff"> 

      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
              Storyboard.TargetName="HoverRectangle" 
              Storyboard.TargetProperty="(UIElement.Opacity)"> 
       <SplineDoubleKeyFrame KeyTime="00:00:00.4000000" 
            Value="0" /> 
      </DoubleAnimationUsingKeyFrames> 

      </Storyboard> 
      <Storyboard x:Key="SelectedOn"> 

      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
              Storyboard.TargetName="SelectedRectangle" 
              Storyboard.TargetProperty="(UIElement.Opacity)"> 
       <SplineDoubleKeyFrame KeyTime="00:00:00.1000000" 
            Value="1" /> 
      </DoubleAnimationUsingKeyFrames> 

      </Storyboard> 
      <Storyboard x:Key="SelectedOff"> 

      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
              Storyboard.TargetName="SelectedRectangle" 
              Storyboard.TargetProperty="(UIElement.Opacity)"> 
       <SplineDoubleKeyFrame KeyTime="00:00:00.4000000" 
            Value="0" /> 
      </DoubleAnimationUsingKeyFrames> 

      </Storyboard> 

     </ControlTemplate.Resources> 
     <Grid SnapsToDevicePixels="true" 
       Margin="1" 
       IsHitTestVisible="True"> 
      <Rectangle x:Name="Background" 
        IsHitTestVisible="True" 
        Opacity="0.25" 
        Fill="{StaticResource NormalBrush}" 
        RadiusX="1" 
        RadiusY="1" /> 
      <Rectangle x:Name="HoverRectangle" 
        IsHitTestVisible="True" 
        Opacity="0" 
        Fill="{StaticResource NormalBrush}" 
        RadiusX="1" 
        RadiusY="1" /> 
      <Rectangle x:Name="SelectedRectangle" 
        IsHitTestVisible="False" 
        Opacity="0" 
        Fill="{StaticResource SelectedBackgroundBrush}" 
        RadiusX="1" 
        RadiusY="1" /> 
      <ContentPresenter Margin="5,2,0,2" 
          x:Name="contentPresenter" 
          VerticalAlignment="Center" /> 
      <Rectangle x:Name="FocusVisualElement" 
        Visibility="Collapsed" 
        Stroke="{StaticResource HoverShineBrush}" 
        StrokeThickness="1" 
        RadiusX="1" 
        RadiusY="1" /> 
     </Grid> 
     <ControlTemplate.Triggers> 
      <Trigger Property="IsHighlighted" 
        Value="true"> 
      <Trigger.ExitActions> 
       <BeginStoryboard Storyboard="{StaticResource SelectedOff}" 
           x:Name="SelectedOff_BeginStoryboard" /> 
      </Trigger.ExitActions> 
      <Trigger.EnterActions> 
       <BeginStoryboard Storyboard="{StaticResource SelectedOn}" 
           x:Name="SelectedOn_BeginStoryboard" /> 
      </Trigger.EnterActions> 

      </Trigger> 
      <Trigger Property="IsMouseOver" 
        Value="True"> 
      <Trigger.ExitActions> 
       <BeginStoryboard Storyboard="{StaticResource HoverOff}" 
           x:Name="HoverOff_BeginStoryboard" /> 
      </Trigger.ExitActions> 
      <Trigger.EnterActions> 
       <BeginStoryboard Storyboard="{StaticResource HoverOn}" /> 
      </Trigger.EnterActions> 
      </Trigger> 
      <Trigger Property="IsEnabled" 
        Value="false"> 
      <Setter Property="Foreground" 
        Value="{DynamicResource DisabledForegroundBrush}" /> 
      </Trigger> 
     </ControlTemplate.Triggers> 
     </ControlTemplate> 
    </Setter.Value> 
    </Setter> 
</Style> 

<Style x:Key="{x:Static ToolBar.ComboBoxStyleKey}" 
     TargetType="{x:Type ComboBox}"> 
    <Setter Property="FontSize" 
      Value="10" /> 
    <Setter Property="SnapsToDevicePixels" 
      Value="true" /> 
    <Setter Property="Template" 
      Value="{DynamicResource ComboBoxTemplate}" /> 
    <Setter Property="Foreground" 
      Value="White" /> 
</Style> 

组合框模板:(所述ThicknessConverter用于吐出接收到调试窗口的厚度)

<ControlTemplate x:Key="ComboBoxTemplate" 
       TargetType="{x:Type ComboBox}"> 
    <Grid x:Name="grid"> 
    <Grid.Resources> 
     <converters:ComboBoxThicknessConverter x:Key="thicknessConv" /> 
    </Grid.Resources> 
    <ToggleButton Template="{DynamicResource ComboBoxToggleButton}" 
        BorderThickness="{TemplateBinding BorderThickness}" 
        BorderBrush="{TemplateBinding BorderBrush}" 
        x:Name="ToggleButton" 
        Focusable="false" 
        IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" 
        ClickMode="Press" /> 
    <ContentPresenter HorizontalAlignment="Left" 
         x:Name="ContentSite" 
         Margin="{TemplateBinding BorderThickness, Converter={StaticResource thicknessConv}}" 
         VerticalAlignment="Center" 
         Content="{TemplateBinding SelectedItem}" 
         ContentTemplate="{TemplateBinding ItemTemplate}" 
         ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" 
         IsHitTestVisible="False" /> 
    <Popup IsOpen="{TemplateBinding IsDropDownOpen}" 
      Placement="Bottom" 
      x:Name="Popup" 
      Focusable="False" 
      AllowsTransparency="True" 
      PopupAnimation="Slide"> 
     <Grid MaxHeight="{TemplateBinding MaxDropDownHeight}" 
      MinWidth="{TemplateBinding ActualWidth}" 
      x:Name="DropDown" 
      SnapsToDevicePixels="True"> 
     <Border x:Name="DropDownBorder" 
       Background="{DynamicResource ControlBackgroundBrush}" 
       CornerRadius="3" /> 
     <ScrollViewer Margin="4,6" 
         Style="{DynamicResource NuclearScrollViewer}" 
         SnapsToDevicePixels="True" 
         HorizontalScrollBarVisibility="Auto" 
         VerticalScrollBarVisibility="Auto" 
         CanContentScroll="True" 
         Foreground="{DynamicResource {x:Static SystemColors.ActiveCaptionTextBrushKey}}"> 
      <StackPanel IsItemsHost="True" 
         KeyboardNavigation.DirectionalNavigation="Contained" /> 
     </ScrollViewer> 
     </Grid> 
    </Popup> 
    </Grid> 
    <ControlTemplate.Triggers> 
    <Trigger Property="HasItems" 
      Value="false"> 
     <Setter Property="MinHeight" 
       Value="95" 
       TargetName="DropDownBorder" /> 
    </Trigger> 
    <Trigger Property="IsEnabled" 
      Value="false"> 
     <Setter Property="Foreground" 
       Value="{DynamicResource DisabledForegroundBrush}" /> 
     <Setter Property="Opacity" 
       TargetName="grid" 
       Value="0.5" /> 
    </Trigger> 
    <Trigger Property="IsGrouping" 
      Value="true"> 
     <Setter Property="ScrollViewer.CanContentScroll" 
       Value="false" /> 
    </Trigger> 
    <Trigger Property="AllowsTransparency" 
      SourceName="Popup" 
      Value="true"> 
     <Setter Property="Margin" 
       Value="0,2,0,0" 
       TargetName="DropDownBorder" /> 
    </Trigger> 
    <Trigger Property="local:Dragging.IsDragTarget" 
      Value="True"> 
     <Setter Property="BorderBrush" 
       Value="{StaticResource DragTargetBorderBrush}" 
       TargetName="ToggleButton" /> 
    </Trigger> 
    </ControlTemplate.Triggers> 
</ControlTemplate> 

联合mboBoxToggleButton:

<ControlTemplate x:Key="ComboBoxToggleButton" 
       TargetType="{x:Type ToggleButton}"> 
    <Grid x:Name="grid"> 
    <Grid.Resources> 
     <converters:SpecialThicknessConverter x:Key="cv2" /> 
    </Grid.Resources> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition /> 
     <ColumnDefinition Width="20" /> 
    </Grid.ColumnDefinitions> 
    <Rectangle Grid.ColumnSpan="2" 
       HorizontalAlignment="Stretch" 
       x:Name="Rectangle" 
       VerticalAlignment="Stretch" 
       RadiusX="3" 
       RadiusY="3" 
       StrokeThickness="{TemplateBinding BorderThickness, Converter={StaticResource cv2}}" 
       Fill="{DynamicResource LightBrush}" 
       Stroke="{TemplateBinding BorderBrush}" /> 

    <Border Grid.Column="1" 
      Margin="2" 
      Background="{DynamicResource BorderBrush}" 
      CornerRadius="3" 
      x:Name="border" /> 
    <Border Grid.Column="1" 
      Margin="2" 
      Background="{DynamicResource HoverBrush}" 
      CornerRadius="3" 
      x:Name="HoverBorder" 
      Opacity="0" /> 
    <Border Grid.Column="1" 
      Margin="2" 
      Background="{DynamicResource HoverShineBrush}" 
      CornerRadius="3" 
      x:Name="HoverShineBorder" 
      Opacity="0" /> 
    <Path Grid.Column="1" 
      HorizontalAlignment="Center" 
      x:Name="Arrow" 
      VerticalAlignment="Center" 
      Fill="{x:Null}" 
      Data="M0.5,0.5 L3,6.5 5.5,0.5" 
      Stroke="{DynamicResource GlyphBrush}" 
      Margin="5,0" 
      Height="7" 
      StrokeThickness="2" 
      Stretch="Fill" /> 
    <Border Grid.Column="1" 
      Margin="2" 
      Background="{DynamicResource ShineBrush}" 
      CornerRadius="3" 
      x:Name="ShineBorder" /> 
    </Grid> 
    <ControlTemplate.Triggers> 
    <Trigger Property="IsMouseOver" 
      Value="true"> 
     <Trigger.ExitActions> 
     <BeginStoryboard Storyboard="{StaticResource HoverOff}" 
         x:Name="HoverOff_BeginStoryboard" /> 
     </Trigger.ExitActions> 
     <Trigger.EnterActions> 
     <BeginStoryboard Storyboard="{StaticResource HoverOn}" /> 
     </Trigger.EnterActions> 
    </Trigger> 
    <Trigger Property="IsChecked" 
      Value="true" /> 
    <Trigger Property="IsEnabled" 
      Value="False"> 
     <Setter Property="Foreground" 
       Value="{DynamicResource DisabledForegroundBrush}" /> 
     <Setter Property="Stroke" 
       TargetName="Arrow" 
       Value="{DynamicResource DisabledForegroundBrush}" /> 
     <Setter Property="Background" 
       TargetName="border" 
       Value="{DynamicResource DisabledBorderBrush}" /> 
     <Setter Property="Opacity" 
       TargetName="grid" 
       Value="0.8" /> 
    </Trigger> 
    </ControlTemplate.Triggers> 
</ControlTemplate> 

一厚度转换器被用来留下空间边框和路径构成的组合框(20个像素)的右侧的按钮。两者都包括如下:1.

任何想法,我要去哪里:

public class ComboBoxThicknessConverter : IValueConverter 
{ 
    #region IValueConverter Members 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     var oldT = (Thickness)value; 
     //Debug.WriteLine("cbx templ thickness = {" + oldT.Left + ", " + oldT.Top + ", " + oldT.Right + ", " + oldT.Bottom + "}"); 
     return new Thickness(oldT.Left, oldT.Top, oldT.Right + 20, oldT.Bottom); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 

    #endregion 
} 


public class SpecialThicknessConverter : IValueConverter 
{ 
    #region IValueConverter Members 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     var oldT = (Thickness)value; 
     Debug.WriteLine("toggle btn thickness = {" + oldT.Left + ", " + oldT.Top + ", " + oldT.Right + ", " + oldT.Bottom + "}"); 
     return oldT; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 

    #endregion 
} 

除非我手动更改StrokeThickness的ComboBoxToggleButton内的硬编码值,我总是以相同的厚度结束错误?据我所知,我正确地将ComboBox中的BorderThickness沿着每个层次传递到ComboBoxToggleButton中的Rectangle。但是,当我查看调试窗口时,我在ComboBox Style中看到setter中使用的值,而不是在声明ComboBox时使用的值。

在此先感谢!

肖恩

回答

1

TemplateBinding是不一样的作为一个正常的绑定。它被优化以获取特定类型的值并直接传递给相同类型的属性。像转换器,StringFormat等其他选项不能在TemplateBinding上工作,并烦人地不给任何错误。如果您需要做任何转换或试图依靠内置的类型转换到不同类型的属性连接,你需要使用一个正常的绑定使用的RelativeSource TemplatedParent代替:

{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness, Converter={StaticResource cv2}} 
+0

使用与TemplatedParent的绑定是解决方案的一部分。另一部分是我的答案中描述的类型不匹配。谢谢您的帮助。 –

0

最后,问题是Rectangle.Stroke(Shape.StrokeThickness是double)和Control.BorderThickness(它是厚度... 4双打)之间的类型差异。

添加了一个转换器,并使用TemplateBinding在接受的答案建议,它的工作。

StrokeThickness="{Binding BorderThickness, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource rect2DoubleConv}}" 


public class RectangleToDoubleConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     var oldT = (Thickness)value; 
     return (oldT.Left + oldT.Top + oldT.Right + oldT.Bottom)/4.0; 
    } 
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
}