Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF Style Combobox with two columns in dropdown

I've looked around, found some things and now stuck on a combobox with two columns displayed in the drop-down area. I have a xaml themes available and the combobox "Style" is defined and works well throughout as expected, so that part is ok.

Now, I have a combobox that I need to have display two values, think of it as State Abbreviation and State Name for the drop-down, coming from a DataTable.DefaultView binding source for the items.

If I have

<my:cboStates TextSearch.TextPath="StateAbbrev">
  <ComboBox.ItemTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal" TextSearch.Text="{Binding Path=StateAbbrev}">
        <TextBlock Text="{Binding Path=StateAbbrev}"/>
        <TextBlock Text="{Binding Path=FullStateName}" Margin="10 0"/>
      </StackPanel>
    </DataTemplate>
  </ComboBox.ItemTemplate>
</my:cboStates>

this works. Now, how/where I'm stuck... Now, I want this same functionality on say 5 different forms and all to have the same content displayed, and if ever changed (not this, but for other multi-column comboboxes), I don't want to have to keep putting this directly in the form's XAML file.

I was hoping to put into a Theme's Resource Dictionary file and just keep reusing that "style" over and over. Makes sense. However, when I do, and the binding is to the data table, the only results I get when trying to do as a Style is the dropdown shows values of

System.Data.DataRowView
System.Data.DataRowView
System.Data.DataRowView
System.Data.DataRowView

instead of the actual 2 columns. Here is what I have in the "theme" resource dictionary.

<DataTemplate x:Key="myStateComboTemplate" >
  <StackPanel Orientation="Horizontal"  >
    <TextBlock Text="{Binding Path=StateAbbrev}"/>
    <TextBlock Text="{Binding Path=FullStateName}"/>
  </StackPanel>
</DataTemplate>

<Style x:Key="StyleMyStatesCombobox" TargetType="{x:Type ComboBox}" 
  BasedOn="{StaticResource MyOtherWorkingComboBoxStyle}" >
  <Setter Property="TextSearch.TextPath" Value="{Binding Path=StateAbbrev}" />
  <Setter Property="ItemTemplate" Value="{StaticResource myStateComboTemplate}" />
</Style>

So, If I have TWO instances my "cboStates" class created on the form, and set one to the explicit styling listed first, and the SECOND based on the "Style" setting, the second one fails by only showing the repeated System.Data.DataRowView entries, not the actual data content.

What am I missing.

So, to clarify what I'm looking for... States... ex data

AL Alabama
AK Alaska
AZ Arizona
AR Arkansas
CA California
CO Colorado
CT Connecticut
DE Delaware

I want the combobox to be displaying the abbreviated AL, AK, AZ, etc and narrower combobox. This will ALSO be the "SelectedValue" upon return.

The actual Dropdown would present the data as listed above showing BOTH the abbreviation AND the long description of the state.

Sample of desired combobox

enter image description here

like image 832
DRapp Avatar asked Dec 20 '12 19:12

DRapp


1 Answers

FINALLY got it working... and for those attempting similar. Since I was trying to have a standard "class" instance that could be used throughout, but not wanting to explicitly hard-reference the XAML in each page, part of the styling had to be handled during the actual in-code class instance.

Since I don't exactly know how/when where .net framework builds out all its controls, style assigments, etc, I was getting frustrated that it would work if direct from xaml, but fail when in code. So, I ended up FORCING the item template AND TextSearch.TextPath values in the code. Here's a short snippet of the class

public class myStatesCombo : ComboBox
{
   public myStatesCombo()
   {
      Loaded += myAfterLoaded;
   }

   protected static DataTable myTableOfStates;

   public void myAfterLoaded()
   {
      if( myTableOfStates == null )
        myTableOfStates = new DataTable();

      CallProcedureToPopulateStates( myTableOfStates );

      ItemsSource = myTableOfStates.DefaultView;

      // AFTER the object is created, and all default styles attempted to be set,
      // FORCE looking for the resource of the "DataTemplate" in the themes.xaml file
      object tryFindObj = TryFindResource("myStateComboTemplate" );
      if( tryFindObj is DataTemplate )
         ItemTemplate = (DataTemplate)tryFindObj;

      // NOW, the CRITICAL component missed in the source code
      TextSearch.SetTextPath( this, "StateAbbrev" );
   }
}

Now, a special note. In the routine I used to populate the DataTable, I pre-check if the table exists or not. First time in, I create the table. If I need to re-populate it, if I just keep doing a "new DataTable" each time, it blows away the data/item template bindings. To PREVENT that, I would then do

if( myTableOfStates.Rows.Count > 0 )
  myTableOfStates.Rows.Clear();

THEN, I call my

Sqlexecute call to query from the database (DataAdapter) and Fill() the datatable.

So, now all appears to be populated correctly, bindings for display and textsearch complete and ready to go.

like image 197
DRapp Avatar answered Nov 15 '22 00:11

DRapp