2

I've built a custom ComboBox which shows as a TextBox when ReadOnly is set:

<local:BoolToVisibilityConverter FalseValue="Hidden" TrueValue="Visible" x:Key="BoolVis" />
<local:BoolToVisibilityConverter FalseValue="Visible" TrueValue="Hidden" x:Key="BoolVisRev" />

<Style TargetType="{x:Type local:ComboBoxG}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:ComboBoxG}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <Grid>
                        <ComboBox ItemsSource="{TemplateBinding ItemsSource}"
                                  DisplayMemberPath="{TemplateBinding DisplayMemberPath}"
                                  SelectedValuePath="{TemplateBinding SelectedValuePath}"
                                  SelectedIndex="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedIndex, Mode=TwoWay}"
                                  Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsReadOnly, Converter={StaticResource BoolVisRev}}"
                                  IsDropDownOpen="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsDropDownOpen, Mode=TwoWay}"
                                  IsTabStop="False">
                        </ComboBox>
                        <TextBox Text="{TemplateBinding Text}" 
                                 Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsReadOnly, Converter={StaticResource BoolVis}}"
                                 IsTabStop="False">
                        </TextBox>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

It's working fine, other than if I instantiate and set a value all in one go. This doesn't work ...

private void One_OnClick(object sender, RoutedEventArgs e)
{
    cmb = new ComboBoxG();
    Stack.Children.Add(cmb);

    var dict = new Dictionary<int, string> { { 0, "aaa" }, { 1, "bbb" }, { 2, "ccc" }, { 3, "ddd" }, };
    cmb.ItemsSource = dict;
    cmb.DisplayMemberPath = "Value";
    cmb.SelectedValuePath = "Key";
    cmb.SelectedValue = 3;
}

... whereas this does ...

private void One_OnClick(object sender, RoutedEventArgs e)
{
    cmb = new ComboBoxG();
    Stack.Children.Add(cmb);

    var dict = new Dictionary<int, string> { { 0, "aaa" }, { 1, "bbb" }, { 2, "ccc" }, { 3, "ddd" }, };
    cmb.ItemsSource = dict;
    cmb.DisplayMemberPath = "Value";
    cmb.SelectedValuePath = "Key";
    cmb.Loaded += cmb_Loaded;
}

private void cmb_Loaded(object sender, RoutedEventArgs e)
{
    cmb.SelectedValue = 3;
}

So I can work around it but it is making it awkward for some uses of this control. Any suggestions, please?

4

3 回答 3

1

我之前也遇到过这种情况,到目前为止,唯一一种半愉快的解决方法是让消息队列通过 Loaded 阶段排出。请注意,我对此并不感到自豪,但 WPF 分阶段进行,有时您希望将所有内容放在一起。我想您可以将 cmd.SelectedValue = 3 放入委托中,但这只是口味问题...

        cmb = new ComboboxG();
        theStack.Children.Add(cmb);

        var dict = new Dictionary<int, string> { { 0, "aaa" }, { 1, "bbb" }, { 2, "ccc" }, { 3, "ddd" }, };
        cmb.ItemsSource = dict;
        cmb.DisplayMemberPath = "Value";
        cmb.SelectedValuePath = "Key";

        Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.Loaded);

        cmb.SelectedValue = 3;

请注意,这将允许事件运行,因此请注意重入!

于 2013-02-03T00:23:18.807 回答
0

尝试设置 SelectedItem 而不是 Index

于 2013-02-01T12:48:07.973 回答
0

您是否尝试过设置选定的索引?

private void One_OnClick(object sender, RoutedEventArgs e)
{
    cmb = new ComboBoxG();
    Stack.Children.Add(cmb);

    var dict = new Dictionary<int, string> { { 0, "aaa" }, { 1, "bbb" }, { 2, "ccc" }, { 3, "ddd" }, };
    cmb.ItemsSource = dict;
    cmb.DisplayMemberPath = "Value";
    cmb.SelectedValuePath = "Key";
    cmb.SelectedIndex = 3;
}
于 2013-02-01T12:24:31.333 回答