I can't find any documentation on how to size the dropdown portion of the combobox. I have two columns and 4 or 5 rows. I want all columns and rows to be visible when the use expands their selections. Right now it's only as wide as the combo and it's showing less than one row.
Thank you.
Mike
Hi Mike,
I've been looking into your requirements and I believe I have the right sample for you. This sample demonstrates how to change the dropdown width. The sample also automatically sizes the dropdown width to show all the columns.
In the sample I handle the dropdown opening event and inside this event I traverse the visual tree of the combo editor to get the Popup that is used for the dropdown. From the Popup it's possible to change the width and height of the dropdown.
Let me know if you have any questions on this.
Rob, this is really great. I actually saw the project in another answer and started working with it this morning.
I can see in your example that the two string columns are sized correctly, however in my situation I have an image column and a string column. For some reason in the popup_Opened event around line 53, I only have one control in the itemsPanel. In your example, both of your columns show up, but in mine, only the first one will show up.
My xaml code is as follows:
<ig:XamMultiColumnComboEditor x:Name="cbInternalSecretion" Width="93" VerticalAlignment="Bottom" AllowMultipleSelection="False" DisplayMemberPath="PickListItem" AutoGenerateColumns="False" SelectedItemsResetButtonVisibility="Collapsed" ItemsSource="{Binding DataContext.InternalSecretion, ElementName=LayoutRoot, Mode=OneWay}" SelectedItem="{Binding DataContext.InternalSecretionSelectedItem, ElementName=LayoutRoot, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" SelectionChanged="cbInternalSecretion_SelectionChanged" Loaded="cbInternalSecretion_Loaded" Panel.ZIndex="0"> <ig:XamMultiColumnComboEditor.Resources> <Style TargetType="{x:Type ig:ComboHeaderCellControl}"> <Style.Triggers> <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Content}" Value="{x:Null}"> <Setter Property="Visibility" Value="Collapsed" /> </DataTrigger> </Style.Triggers> </Style> <Style TargetType="{x:Type ig:ComboCellControl}"> <Style.Triggers> <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=HasContent}" Value="False"> <Setter Property="Visibility" Value="Collapsed" /> </DataTrigger> </Style.Triggers> </Style> </ig:XamMultiColumnComboEditor.Resources> <ig:XamMultiColumnComboEditor.Columns> <ig:TextComboColumn Key="PickListItem" HeaderText="Infection Classification" /> <ig:ImageComboColumn Key="Thumbnail" HeaderText="Thumbnail Photo" /> </ig:XamMultiColumnComboEditor.Columns> </ig:XamMultiColumnComboEditor>
My code behind is almost exactly what is in your sample except for a check on the child count which I added to prevent a zero value exception.
private void cbInternalSecretion_Loaded( object sender, RoutedEventArgs e ) { try { if( VisualTreeHelper.GetChildrenCount( sender as XamMultiColumnComboEditor ) > 0 ) { Grid grid = VisualTreeHelper.GetChild( sender as XamMultiColumnComboEditor, 0 ) as Grid; Popup popup = ( ( grid.Children[ 0 ] as Border ).Child as Grid ).Children[ 0 ] as Popup; // This will change the white space to gray, you really can't get rid of the space though unless the dropdown size // is restricted. ( ( popup.Child as Grid ).Children[ 0 ] as Border ).Background = new SolidColorBrush( Colors.Gray ); // Handle the popup opened event. The grid rows will exist by the time this event is fired. popup.Opened += new EventHandler( popup_Opened ); } } catch( Exception ) { throw; } } void popup_Opened( object sender, EventArgs e ) { Popup popup = sender as Popup; DependencyObject itemsPanel = FindFirstRow( popup.Child ); if( itemsPanel != null && VisualTreeHelper.GetChildrenCount( itemsPanel ) > 0 ) { double width = 0; for( int i = 0; i < VisualTreeHelper.GetChildrenCount( itemsPanel ); i++ ) { ComboCellControl control = VisualTreeHelper.GetChild( itemsPanel, i ) as ComboCellControl; width += control.ActualWidth; } ( ( popup.Child as System.Windows.Controls.Grid ).Children[ 0 ] as Border ).Width = width + 3; popup.MaxWidth = width + 3; } } /// <summary> /// Helper method used to find the first grid row in the visual tree. /// </summary> /// <param name="root"></param> /// <returns></returns> private DependencyObject FindFirstRow( DependencyObject root ) { for( int i = 0; i < VisualTreeHelper.GetChildrenCount( root ); i++ ) { DependencyObject dObj = VisualTreeHelper.GetChild( root, i ); if( dObj.GetType() == typeof( ComboCellsPanel ) ) { return dObj; } dObj = FindFirstRow( dObj ); if( dObj != null ) { return dObj; } } return null; }
Any thoughts?
Thanks,
You should be able to get the height the same way you get the width. I've attached a sample that demonstrates setting both the width and height of the dropdown to show all the items in the grid. I've made some modifications to my previous sample to accomodate the extra code but the basic premise is still the same. To get the height of a row I first grab the header row and then the row after that in the rows collection. Then I use the ActualHeight property on the non-header row and multiply that by the number of rows in the grid and store this value. Afterwards I add the header row's height to this value and this gives you the total height used by the grid. Width in this case is still calculated the same as before but I add a bit of a buffer to it, just enough to make the width large enough so the scrollbar disappears.
Rob,
Thanks again for your time. I did try resetting the height of the popup, but no matter what I set it to it would only show 2 1/3 rows. I'll take a look at your sample and then get back to you.
I saw how you changed your code, and what you did was very interesting. thank you for your help.
I have an additional question here that is vexing me. In the line where you are getting the actual row panel's actual height, sometimes the value is 66.0 pixels which is correct. However sometimes the value is 21.96 which is not correct and I can't understand why that would be since every row has a picture in it and every row should be 66.0. Do you have any thoughts about it? I have 8 combo boxes for different phases of diagnosis and they all come from the same object list. For now I am hard coding this value, but I don't understand why sometimes the first row is 66.0 and then at other times it is 21.96.
The row that has a height of 21.96 is the header row. I was under the impression from my own tests though that the header panel was always first in the MultiColumnComboItemsPanel container but in your case you're saying that isn't always the case.
To remedy this you will need to modify the code a bit to perform a search for the header row and then search for the first non-header row. You can then multiply the height of the non-header row by the number of rows and add the header row height to the result. Something like this:
ComboCellsPanel headerPanel = null; ComboCellsPanel actualRowPanel = null; foreach (ComboCellsPanel panel in itemsPanel.Children) { if (panel.Row is ComboHeaderRow) headerPanel = panel; else if (actualRowPanel == null) actualRowPanel = panel; } double totalHeight = actualRowPanel.ActualHeight * numRows + headerPanel.ActualHeight;
Thanks for your help on these final details. I'll look at this later today and get back with you.
You have been very helpful to me.
Let me know if you have any further questions on this matter.
Sounds good. Let me know how it goes.