WPF ComboBox最初显示错误大小的第一个项目

时间:2011-07-06 13:08:42

标签: wpf user-controls combobox

我在WPF窗口上有一个ComboBox给了我一些心痛,因为在第一次显示时,第一个选择被不正确地呈现。 ComboBox不显示文本;它显示一个从UserControl下降的类型的对象。这是ComboBox本身的XAML:

<ComboBox Grid.Column="0" 
          Height="69" 
          HorizontalAlignment="Stretch"
          HorizontalContentAlignment="Center"
          ItemsSource="{Binding Path=ViewChoices, 
                        RelativeSource={RelativeSource AncestorType={x:Type UserControl}},  
                        Mode=OneWay}" 
          Margin="10" 
          Name="ViewPicker" 
          SelectionChanged="ViewPicker_SelectionChanged" 
          VerticalAlignment="Stretch" 
          VerticalContentAlignment="Center" />

如您所见,ComboBox的ItemsSource绑定到拥有它的UserControl属性ViewChoices。 ViewChoices对象是一个ObservableCollection。

ComboBox的内容在后面的代码中的代码中设置,因为最终代码中的确切内容将从XML文件中读取;这些值现在是硬编码的。实质上,为读取的每个XML行创建一个CameraViewChoice对象,并将其添加到ViewChoices集合中。这一切都发生在UserControl的默认构造函数中,在调用InitializeComponent()之后。在UserControl的Loaded事件处理程序中,我有代码将ComboBox的SelectedIndex属性设置为0。

CameraViewChoice对象来自UserControl。这是该控件的Xaml:

<UserControl x:Class="CarSystem.CustomControls.CameraViewChoice"
             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:cs="clr-namespace:CarSystem.CustomControls"  
             mc:Ignorable="d" 
             d:DesignHeight="50" d:DesignWidth="50">

    <Border BorderBrush="Black" BorderThickness="1">
        <Grid>
            <Image Opacity="0.35" Source="..." Stretch="Uniform" />
            <Label Content="{Binding Path=Text}" 
                   FontSize="18" 
                   FontWeight="Bold" 
                   Foreground="White" 
                   HorizontalAlignment="Center" 
                   VerticalAlignment="Center" />
        </Grid>
    </Border>

</UserControl>

这是CameraViewChoice对象的代码隐藏:

public partial class CameraViewChoice : UserControl {

    public static readonly DependencyProperty AttachedCameraProperty =  DependencyProperty.Register( "AttachedCamera", typeof( Camera ), typeof( CameraViewChoice ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsRender ) );

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register( "Text", typeof( string ), typeof( CameraViewChoice ), new FrameworkPropertyMetadata( string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsParentMeasure | FrameworkPropertyMetadataOptions.AffectsRender ) );

    public Camera AttachedCamera {
        get { return (Camera) GetValue( AttachedCameraProperty ); }
        set { SetValue( AttachedCameraProperty, value ); }
    }

    public string Text {
        get { return (string) GetValue( TextProperty ); }
        set { SetValue( TextProperty, value ); }
    }

    public CameraViewChoice() {
        InitializeComponent();
    }

这一切都运转良好,但有一个问题。当程序开始运行并且第一次显示ComboBox时,所选项目显示全部错误。标签为空白,CameraViewChoice控件显示得太大,以至于它的底部被切断。我看到的是一个空白的CameraViewChoice对象,无需缩放到ComboBox。

如果我在列表中选择一个项目,则列表中的所有选项都会正确显示并且大小合适。之后看起来很好,包括选定的一个。问题仅在首次显示窗口时。

有没有人对正在发生的事情有任何想法?

编辑:

我对Google&amp; amp;做了一些研究。 MSDN杂志和我发现了Josh Smith关于数据模板的一篇文章。从那里,我对我的ComboBox的XAML进行了以下更改:

<ComboBox Grid.Column="0" 
          Height="69" 
          HorizontalAlignment="Stretch"
          HorizontalContentAlignment="Center"
          ItemsSource="{Binding Path=ViewChoices, 
                        RelativeSource={RelativeSource AncestorType={x:Type UserControl}},  
                        Mode=OneWay}" 
          Margin="10" 
          Name="ViewPicker" 
          SelectionChanged="ViewPicker_SelectionChanged" 
          VerticalAlignment="Stretch" 
          VerticalContentAlignment="Center">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <cs:CameraViewChoice Margin="10" />
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

这更好,因为ComboBox中的项目不会改变大小,但初始显示仍然太大。也就是说,它在底部被切断了。此外,所选项目的大小始终太大。因此,当您在列表中选择一个项目时,它会显示在部分剪裁的组合框中。

我想要在ComboBox中显示的选项,其中所有选项都适合它。有关更改CombobBox的ItemTemplate的建议吗?

2 个答案:

答案 0 :(得分:1)

这就是我认为正在发生的事情。

您正在使用标准ComboBox并动态添加UIElements。首次显示ComboBox时,没有项目,因此它使用默认模板。在您开始向其添加UIElements之后,渲染器会执行测量和排列。从本质上讲,它只是在创建和插入UIElements后才能学习它应该是什么样子(但它仍然需要知道在发生之前看起来像什么)。

我的建议是从这种发展模式转向更常见的方法。而不是动态创建UIElements,只需创建一个ObservableCollection的CameraChoices(或任何适当的名称)。通常,这将包含在ViewModel中。

然后,不是创建UserControl并将其插入到ComboBox的ItemsSource中,而是更好地为ComboBox创建ItemsTemplate(您可以在其中使用UserControl)。或者,您可以使用与ObservableCollection中的对象相同类型的DataTemplate。

这将为显示项目列表提供更强大的机制,并为您提供获取原始数据的方法,而不是在发出SelectionChanged事件时必须处理UIElement。

答案 1 :(得分:1)

在Loaded事件中,如果您至少有2个项目,请将SelectedIndex设置为1.在此之后,无论您有多少项目,请在ComboBox上调用InvalidateMeasure和UpdateLayout,然后将SelectedIndex设置为0。