4

I have managed to create a ComboBox with treeview as its itempresenter using the selected item behavior here.

<Popup x:Name="PART_Popup" AllowsTransparency="true" Focusable="false" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
    <Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{TemplateBinding ActualWidth}">
        <Border x:Name="DropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
        <ScrollViewer>
            <TreeView  x:Name="PART_TreeView" ItemsSource="{TemplateBinding ItemsSource}">
                <Interactivity:Interaction.Behaviors>
                <ComboTreeView:BindableSelectedItemBehaviour SelectedItem="{Binding RelativeSource={RelativeSource AncestorType={x:Type ComboBox} }, Path=SelectedItem, Mode=TwoWay}" />    
                </Interactivity:Interaction.Behaviors>                                                  
                </TreeView>                             
        </ScrollViewer>
        </Border>
    </Microsoft_Windows_Themes:SystemDropShadowChrome>
</Popup>

Selecting an item in treeview correctly sets the combobox selected item. I am not sure how to close the pop up on selection. Everytime I have to select and click outside the control for the popup to go away. Can this be done in XAML ?

Community
  • 1
  • 1
anivas
  • 6,437
  • 6
  • 37
  • 45

3 Answers3

3

I do not believe that it can be done in XAML, but it could be done in codebehind:

void EnsureComboPopupClosed(ComboBox cb)
{
    if (cb == null || cb.Template == null)
        return;
    Popup popup = cb.Template.FindName("PART_Popup", cb) as Popup;
    if (popup == null)
        return;
    popup.IsOpen = false;
}

You could use an event handler to call this function.

Ed Bayiates
  • 11,060
  • 4
  • 43
  • 62
0

I did this in xaml ala an Event Trigger. If anyone has any optimizations for this, then by all means, please suggest away, I'm pretty green with this.

UPDATE ... and this partially works, except now the ComboBox will not open again after you selected and item in the tree.

... xmlns:s="clr-namespace:System;assembly=mscorlib" ...
...
<ControlTemplate.Resources>
    ....
    <Storyboard x:Key="ClosePopup"
                Duration="0:0:0"
                Storyboard.TargetName="PART_Popup"
                Storyboard.TargetProperty="IsOpen" >
        <ObjectAnimationUsingKeyFrames>
            <DiscreteObjectKeyFrame KeyTime="0:0:0">
                <DiscreteObjectKeyFrame.Value>
                    <s:Boolean>False</s:Boolean>
                </DiscreteObjectKeyFrame.Value>
            </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
    ...
</ControlTemplate.Resources>
    ...
    <TreeView  x:Name="PART_TreeView" ... >
        ...
        <TreeView.Triggers>
            <EventTrigger RoutedEvent="TreeView.SelectedItemChanged">
                <EventTrigger.Actions>
                    ...
                    <BeginStoryboard Storyboard="{StaticResource ClosePopup}"/>
                </EventTrigger.Actions>
            </EventTrigger>
        </TreeView.Triggers>
        ...
    </TreeView>
    ...
David
  • 19,389
  • 12
  • 63
  • 87
0

In the behavior BindableSelectedItemBehaviour, I added the following logic. I think I'll move this to a new behavior, but this works.

    private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        this.SelectedItem = e.NewValue;

        var treeView = (TreeView)sender;
        var control = (FrameworkElement)treeView.TemplatedParent;
        ComboBox combo;

        do
        {
            combo = control as ComboBox;

            if (combo != null)
            {
                break;
            }
        }
        while ((control = (FrameworkElement)control.TemplatedParent) != null);

        if (combo == null)
        {
            return;
        }

        Dispatcher.BeginInvoke(new Action(() => combo.IsDropDownOpen = false));
    }
David
  • 19,389
  • 12
  • 63
  • 87