Popup coordinates within ComboBox template?
I'm trying to make a ComboBox where the DropDown or Popup is Right aligned where there is not enough space on the right hand side of the ComboBox.
I can get it to right align by setting it's FlowDirection to RightToLeft but I need to know when to Right align it. So I'm trying to calculate the right edge of the Popup by using it's X-Coordinate (relative to the RootVisual) plus it's width. If it's right edge's value is more than the width of the RootVisual then the ComboBox needs the Right align it's Popup or DropDown.
Now my problem is that it looks to me that the Popup is inheriting the ComboBox's Coordinates. Why do I get the incorrect Coordinates for the Popup? Is it because the Popup is contained inside the template for the ComboBox? Here is my sample code...
The ComboBox's simplified template...
<Style TargetType="local:CustomComboBox">
<Setter Property="Padding" Value="6,2,25,2"/>
<Setter Property="Background" Value="#FF1F3B53"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="TabNavigation" Value="Once"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFA3AEB9" Offset="0"/>
<GradientStop Color="#FF8399A9" Offset="0.375"/>
<GradientStop Color="#FF718597" Offset开发者_如何学JAVA="0.375"/>
<GradientStop Color="#FF617584" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:CustomComboBox">
<Grid>
<Border x:Name="ContentPresenterBorder">
<Grid>
<ToggleButton x:Name="DropDownToggle" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Right" Margin="0" Style="{StaticResource comboToggleStyle}" VerticalAlignment="Stretch">
<Path x:Name="BtnArrow" Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z " HorizontalAlignment="Right" Height="4" Margin="0,0,6,0" Stretch="Uniform" Width="8">
<Path.Fill>
<SolidColorBrush x:Name="BtnArrowColor" Color="#FF333333"/>
</Path.Fill>
</Path>
</ToggleButton>
<ContentPresenter x:Name="ContentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<TextBlock Text=" "/>
</ContentPresenter>
</Grid>
</Border>
<Popup x:Name="Popup">
<Border x:Name="PopupBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="3" HorizontalAlignment="Stretch" Height="Auto">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFFFFFFF" Offset="0"/>
<GradientStop Color="#FFFEFEFE" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<ScrollViewer x:Name="ScrollViewer" BorderThickness="0" Padding="1">
<ItemsPresenter/>
</ScrollViewer>
</Border>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The Control's code behind...
public class CustomComboBox : ComboBox
{
private Popup _popup;
private ScrollViewer _scrollViewer;
public CustomComboBox()
{
this.DefaultStyleKey = typeof(CustomComboBox);
}
protected override void OnDropDownOpened(EventArgs e)
{
GeneralTransform gt = _popup.TransformToVisual(App.Current.RootVisual as UIElement);
Point popupOffset = gt.Transform(new Point(0, 0));
double popupRightEdge = popupOffset.X + _popup.ActualWidth;
double appRightEdge = (App.Current.RootVisual as FrameworkElement).ActualWidth;
if (popupRightEdge > appRightEdge)
{
_popup.FlowDirection = FlowDirection.RightToLeft;
_scrollViewer.FlowDirection = FlowDirection.LeftToRight;
}
base.OnDropDownOpened(e);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_popup = GetTemplateChild("Popup") as Popup;
_scrollViewer = GetTemplateChild("ScrollViewer") as ScrollViewer;
}
}
The ValidationErrorElement in the ComboBox's ControlTemplate caused the Popup to Right Align to itself rather than the right edge of the actual ComboBox. I recommend changing the Popup control's name, which is "Popup", to something like "DropDownPopup" in the ControlTemplate for the ComboBox though and then Bind your Popup's IsOpen property to the IsChecked property of the ToggleButton. The Popup is a Control Part of the ComboBox and I suspect there is some code hooked up to it to make it behave the way it does.
Also the Virtualizing StackPanel we used increased performance but created some other odd behavior. Setting a fixed width on the Virtualizing StackPanel fixed it. Setting a Fixed width on the Popup also fixes this.
精彩评论