How to do text search in DropDown of ComboBox with IsEditable=false - wpf

I have a ComboBox with IsEditable = false. When the user drops down the list, I'd like to support him in searching for the right item, by scrolling to the first item that fits to a letter the user types.
So when the DropDown is open and the user types 'S', I'd like him to scroll to the first item (in my case: customer) whose name starts with 'S'.
I can't use the built-in text search because the ComboBox's IsEditable is false. The user can only select one of the proposed values (customers).
How can I do text search anyway? Here is my code:
<ComboBox x:Name="cmbCustomer"
ItemsSource="{Binding LstAllCustomers, Mode=TwoWay}"
SelectedItem="{Binding SelectedCustomer, Mode=TwoWay}"
ItemContainerStyle="{StaticResource customerListStyle}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="2" Text="{Binding ID}"/>
<TextBlock Margin="2" Text="{Binding LastName}"/>
<TextBlock Margin="2" Text="{Binding FirstName}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

Set the IsTextSearchEnabled property to true and the TextSearch.TextPath attached property to either "LastName" or"FirstName" or whatever your property is called:
<ComboBox x:Name="cmbCustomer"
ItemsSource="{Binding LstAllCustomers, Mode=TwoWay}"
SelectedItem="{Binding SelectedCustomer, Mode=TwoWay}"
ItemContainerStyle="{StaticResource customerListStyle}"
IsTextSearchEnabled="True" TextSearch.TextPath="LastName">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="2" Text="{Binding ID}"/>
<TextBlock Margin="2" Text="{Binding LastName}"/>
<TextBlock Margin="2" Text="{Binding FirstName}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
This should work even if you don't set the IsEnabled property to true, assuming that your Customer class actually has a LastName property.

Related

The tapped on comboBox work incorrectly

I have comboBox with names list . When I try to select a name in the list, it generally takes 3-5 clicks on the selected name.
<ComboBox
Grid.Row="6"
Height="50"
Margin="0,20,0,0"
Name="AssetClassComboBox"
HorizontalAlignment="Stretch"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
ItemsSource="{x:Bind ListAssetClass, Mode=OneWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="models:ComboBoxAssetClassItem">
<ComboBoxItem Content="{x:Bind Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
If I delete this code the comboBox works correctly, the list is visible, but I cannot see the names.
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="models:ComboBoxAssetClassItem">
<ComboBoxItem Content="{x:Bind Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
Instead of creating a ItemTemplate you could simply use the property DisplayMemberPath of ComboBox:
<ComboBox
...
DisplayMemberPath="Name"
ItemsSource="{x:Bind ListAssetClass, Mode=OneWay}">

How to Bind with a StringFormat

I have a ComboBox which I am binding to an IEnumerable<int> source.
The source has values like 12,13,14 but I want the ComboBox to display Version 12, Version 13, Version 14 etc with SelectedValue still 12, 13 and 14.
For now I am modifying the Source to add Version to it and then Binding the ComboBox to an IEnumerable.
XAML
<ComboBox x:Name="ComboBoxVersions"
SelectedIndex="0"
SelectionChanged="ComboBoxVersions_OnSelectionChanged"
ItemsSource="{Binding EnvironmentVersions}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
You could use something like this
<TextBlock Text="{Binding StringFormat=Version: {0}}" />
using ComboBox.ItemStringFormat:
<ComboBox ItemsSource="{Binding EnvironmentVersions}"
ItemStringFormat="version: {0}" />
or using ComboBox.ItemTemplate
<DataTemplate>
<TextBlock Text="{Binding StringFormat=Version: {0}}" />
</DataTemplate>
or
<DataTemplate>
<TextBlock>
<Run Text="Version " />
<Run Text="{Binding }"/>
</TextBlock>
</DataTemplate>
Here's a simple way:
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Version " />
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
Since the ItemTemplate only defines how the items are displayed, the SelectedItem property of the ComboBox still holds the original value from your collection of version numbers.
You can add a string format to the binding in the datatemplate.
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding StringFormat=Version {0}}" />
</DataTemplate>
</ComboBox.ItemTemplate>

how to bind the selected item from the combobox to textblock inside datagrid

I am having combobox inside datagrid which is inside cell editing template.
What i want is that when a user select an item from the combobox and move to the next cell, the selected item must bind to the textblock of that same cell.
if anyone knows how to do help me. here is my xaml
<DataGrid AutoGenerateColumns="False" VirtualizingStackPanel.IsVirtualizing="False"
Grid.Row="1" Grid.ColumnSpan="7" Name="attendancegrid" Background="#FFDCE8EB" CanUserAddRows="False"
BorderBrush="Chocolate" BorderThickness="5" RowHeight="30" IsSynchronizedWithCurrentItem="True"
HorizontalGridLinesBrush="#FFB74646" IsReadOnly="False" Foreground="Black" Loaded="attendancegrid_Loaded"
SelectionChanged="attendancegrid_SelectionChanged" CurrentCellChanged="attendancegrid_CurrentCellChanged"
CellEditEnding="attendancegrid_CellEditEnding">
<DataGridTemplateColumn Header="Monday" Width="100">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox x:Name="monday" Width="50" IsSynchronizedWithCurrentItem="true" Loaded="monday_Loaded" SelectionChanged="monday_SelectionChanged"></ComboBox>
<ComboBox x:Name="staff" Width="50" Loaded="staff_Loaded"></ComboBox>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel >
<TextBlock x:Name="mon"></TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid>
You have to create one collection property to be bound on Combobox like
public List<string> MyCollection{get;set;}
and one string property for binding it to the SelectedItem of ComboBox and Your TextBlock like
private string _SelectedCollectionItem;
public string SelectedCollectionItem
{
get{return _SelectedCollectionItem;}
set{_SelectedCollectionItem=value;
RaisePropertyChanged("SelectedCollectionItem");}
}
now in your xaml do like this
DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding MyCollection}" SelectedItem={Binding SelectedCollectionItem,Mode=TwoWay}></ComboBox>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel >
<TextBlock Text={Binding SelectedCollectionItem}></TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>

Binding inside listbox itemtemplate problems

I have two separate binding problems with listboxes with an itemtemplate which contains a texbox.
1) One listbox binds to a list of strings. How can I display each string inside the textboxes created and allow two way binding at the same time? Two way binding isn't allowed without specifying a Path or XPath.
<ListBox Height="231" HorizontalAlignment="Left" Margin="0,167,0,0" Name="listBoxKeys" VerticalAlignment="Top" Width="219" ItemsSource="{Binding Path=SelectedPlatform.Keys}" SelectedItem="{Binding Path=SelectedKey,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
<TextBox Text="{Binding Mode=OneWay}" Margin="0,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And 2) I use another listbox which binds to some generic list of a custom KeyValuePair class. The itemtemplate contains a textbox and combobox. The textbox text is bound to the key property of each KeyValuePair object and the combobox selecteditem to the value property. My problem is that I want the combo to get filled by a list of strings declared in my viewmodel which will be changing on runtime. The window's datacontext is the viewmodel where the list is declared. I don't know the exact syntax I need to use to bind the combobox itemssource there. Here's my code :
<ListBox Height="393" HorizontalAlignment="Left" Margin="0,72,0,0" Name="listBoxActions" VerticalAlignment="Top" Width="254" ItemsSource="{Binding Path=SelectedPlayer.ControlProfile.MappedActions}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
<TextBox Text="{Binding Key, Mode=TwoWay,UpdateSourceTrigger=LostFocus}" Margin="10,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<ComboBox Margin="10,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center" ItemsSource="{Binding ?}" SelectedItem="{Binding Value, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The problem is that the two-way binding on the source itself cannot work because it would mean that the whole object (string), for which the data template is created, must be replaced when user changes the text in the text box. Obviously, this will not work. Two-way binding will work only on a writable property of the bound object.
In your case I would suggest creating a view model for the items in the list box (basically a view model for your strings) and expose a Value property on it and bind to it in the data template:
<ListBox Height="231" HorizontalAlignment="Left" Margin="0,167,0,0"
Name="listBoxKeys" VerticalAlignment="Top" Width="219"
ItemsSource="{Binding Path=SelectedPlatform.KeyViewModels}"
SelectedItem="{Binding Path=SelectedKey,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
<TextBox Text="{Binding Value, Mode=TwoWay}" Margin="0,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
1) Pavlo Glazkov seems to have a good answer to me
2) This is down to the DataContext for the ComboBox now being the key value pair rather than the ViewModel. There may be other ways to do this but the one that I've used before is to set the bindings RelativeSource source back to it's parent ItemsControl.
RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}
Something like:
<ListBox Height="393" HorizontalAlignment="Left" Margin="0,72,0,0" Name="listBoxActions" VerticalAlignment="Top" Width="254" ItemsSource="{Binding Path=SelectedPlayer.ControlProfile.MappedActions}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
<TextBox Text="{Binding Key, Mode=TwoWay,UpdateSourceTrigger=LostFocus}" Margin="10,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<ComboBox Margin="10,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center" ItemsSource="{Binding DataContext.Keys, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" SelectedItem="{Binding Value, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Telerik RadComboBox not showing Selected Item

I have a RadComboBox that i have bound like shown below
<telerik1:RadComboBox Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3" Margin="5,2" ItemsSource="{Binding RepTypes}" DisplayMemberPath="Path=TypeName" SelectedValuePath="Value" SelectedItem="{Binding RepType, Mode=TwoWay}" >
</telerik1:RadComboBox>
When i select an Item I catch the Property Changed event, but basically the selection in the combo box stays blank.
What am i doing wrong?
Ok i made it so that it shows up now.. But i don't understand why... Or how to change it so it works for me in all cases...
<telerik1:RadComboBox Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3" Margin="5,2" ItemsSource="{Binding RepTypes}" SelectedValuePath="Value" SelectedItem="{Binding RepType, Mode=TwoWay}" >
</telerik1:RadComboBox>
Thats what works... the Biggest difference was. I had to name a field to "Name" and then bind it and take out the DisplayMemberPath="Path=ReportName"
If that is the case then how do i tell the control what Field to Display in the dropdown?
Are you somehow changing your collection? The controls only look for the items once. So, if the page loads and then you're loading your collection of RepTypes, it doesn't update the dictionary. I'm doing something similar and I'm lazy loading my collection (as you type, I get more from the database).
<t:RadComboBox x:Name="RepTypeComboBox" Margin="0,1"
t:TextSearch.TextPath="TypeName"
ItemsSource="{Binding Path=RepTypes, Mode=OneWay}"
SelectedValue="{Binding Path=Reptype, Mode=TwoWay, NotifyOnValidationError=True}"
IsEditable="True"
Grid.Column="1"
Grid.Row="2" TabIndex="1">
<t:RadComboBox.ItemTemplate >
<DataTemplate >
<StackPanel Orientation="Horizontal" >
<TextBlock FontWeight="Bold" Text="{Binding Path=TypeName, Mode=OneWay}" Width="75"/>
<TextBlock Text=": " />
<TextBlock Text="{Binding Path=address1, Mode=OneWay}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding Path=address2, Mode=OneWay}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding Path=citystate, Mode=OneWay}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding Path=zip, Mode=OneWay}" />
</StackPanel>
</DataTemplate>
</t:RadComboBox.ItemTemplate>
</t:RadComboBox>
If you want ReportName to be shown as your display member, you only have to put it this way:
<telerik1:RadComboBox ItemsSource="{Binding RepTypes}" SelectedValuePath="Value"
SelectedItem="{Binding RepType, Mode=TwoWay}" DisplayMemberPath="ReportName">
</telerik1:RadComboBox>
You're putting an extra "Path=" that's only confusing the XAML parser.

Resources