Binding Text Property in Autocomplete Combobox - c#

could someone help me to solve an issue with combobox behaviour. Here is my combobox control (WPF):
<ComboBox Grid.Row="1" Grid.Column="1" Margin="6,0,6,6" Name="comboBoxRegionTown" IsEditable="True" IsTextSearchEnabled="True" PreviewKeyUp="comboBoxRegionTown_PreviewKeyUp" IsTextSearchCaseSensitive="False" />
The idea is to make it autocomplete (IsEditable="True" IsTextSearchEnabled="True"). So then I typу any text into combobox it shows some results from database.
Here is a code of comboBoxRegionTown_PreviewKeyUp event (C#):
private void comboBoxRegionTown_PreviewKeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
if (!string.IsNullOrEmpty(comboBoxRegionTown.Text))
{
comboBoxRegionTown.ItemsSource = _br.GetQuery(x => x.Name.Contains(comboBoxRegionTown.Text) && x.RegionTypeId == (int)RegionType.Town).ToList();
comboBoxRegionTown.IsDropDownOpen = true;
}
else
{
comboBoxRegionTown.ItemsSource = null;
}
}
So that works fine for me, but then I click to any found item in combobox it puts into ComboBox.Text property the type of my selected object (in this case - Region). Of course I can override ToString() method for my Region object and set there its public property Name and this solution works fine, but I think the best way is to find how to bind selected item into Text property of my combobox. Is there any way to do this?
I've already tryed to ind Text="{Binding Path=Name}" and/or SelectedItem="{Binding Path=Name}" but in these cases just always get empty Text. Please help.

What you need to do is set the ItemTemplate for your ComboBox, but if you just want to display a single property there's an easier way: set DisplayMemberPath="Name" in the ComboBox and it'll generate the correct template for you.

Related

How to make a combo box display a default item from a list when the window is loaded

I have a WPF applications with a User Control that contains a couple combo boxes. One of the combo boxes is populated and displays the first value because it is bound to an IEnumerable property of enum values. The other is bound to an IEnumerable property of string values. This displays all the choices in the drop down, but does not display a value when it is first loaded. After selecting an option, the user is able to click the clear button, which will remove their selected option, and display the first value in the list until another value is chosen. Is there a way for me to get it to load with the first value already populated as the default value?
User Control:
<ComboBox x:Name="insuranceTypesComboBox" ItemsSource="{Binding Path=InsuranceTypes}" SelectedItem="{Binding Path=FilteredType}" Width="100" />
<ComboBox x:Name="insurancesComboBox" ItemsSource="{Binding Path=Insurances}" SelectedItem="{Binding Path=FilteredPlan}" Width="100"/>
Properties:
public IEnumerable<string> Insurances
{
get
{
var insurances = (from i in this.repository.GetInsurance()
select i.CompanyName).ToList();
return insurances.Distinct();
}
}
public IEnumerable<InsuranceType> InsuranceTypes
{
get
{
return Enum.GetValues(typeof(InsuranceType)) as IEnumerable<InsuranceType>;
}
}
You can select the first item in the combobox by adding SelectedIndex=0 to the xaml. Or try adding UpdateSourceTrigger=PropertyChanged to the selected item binding:
<ComboBox x:Name="insuranceTypesComboBox"
ItemsSource="{Binding Path=InsuranceTypes}"
SelectedItem="{Binding Path=FilteredType, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Width="100"
SelectedIndex="0" />
To set the default item that is selected, just use (for example):
myComboBox.SelectedIndex = 5; // set the 6th item in list as selected
or you can use combobox.SelectedValue.
Make sure that you don't accidentally trigger the index changed event.
please refer selectedindex_selectedvalue

wpf excel like grid editing?

In a project I have a very tricky requirement I don't know how to solve:
I have several datagrids in a single wpf window (I use MVVM) all binded to some collection in the linked ViewModel.
The customer wants to edit each of these grids, either within the grid or in a common textbox (like in excel).
I'm banging the head on how to do the latter. What I would do is bind the textbox with a property in the viewmodel, but when the value is changed there, I need to change the value in the original property binded with the datagrid cell accordingly. In other words, I need to know what collection and which property of that collection I need to change with the data in the textbox accordingly .
I tried several ways but with no luck.
Reflection? DependencyProperty? What else?
Any help?
Thank you
Assuming that you're using the built-in WPF DataGrid, you'll need to setup your grid similarly:
<DataGrid SelectionUnit="Cell" SelectionMode="Single" ItemsSource="{Binding Data}" SelectedCellsChanged="DataGrid_OnSelectedCellsChanged">
...
</DataGrid>
Also give your TextBox a name:
<TextBox x:Name="textBox" DockPanel.Dock="Top" />
In the code-behind, you'll need to manually wire up this event, since apparently the DataGrid doesn't allow you to bind to the selected item/cell/value when using SelectionUnit="Cell":
private void DataGrid_OnSelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
if (e.AddedCells.Count == 0)
this.textBox.SetBinding(TextBox.TextProperty, (string) null);
else
{
var selectedCell = e.AddedCells.First();
// Assumes your header is the same name as the field it's bound to
var binding = new Binding(selectedCell.Column.Header.ToString())
{
Mode = BindingMode.TwoWay,
Source = selectedCell.Item,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
this.textBox.SetBinding(TextBox.TextProperty, binding);
}
}
I tried getting this done without code-behind but after looking around it didn't seem like this was possible.
In addition to tencntraze answer I used this code to get te property bound to the cell
var property = (selectedCell.Column.ClipboardContentBinding as Binding).Path.Path;

Select ComboBox Text

I have a ComboBox declared as follows:
<ComboBox Name="txtUserName" IsEditable="True" />
I want to select the ComboBox's text field on focus, but I can't figure out how to do this. Currently, when the ComboBox is focused on programmatically (through "txtUserName.Focus()"), it allows the user to scroll through the different items, but requires an additional click to highlight the text field.
Any thoughts?
The solution I used was to add the following code to the window's loaded event:
var textBox = (txtUserName.Template.FindName("PART_EditableTextBox", txtUserName) as TextBox);
if (textBox != null)
{
textBox.Focus();
textBox.SelectionStart = textBox.Text.Length;
}
The solution came from one of the suggested answers here: How to add a focus to an editable ComboBox in WPF
Try this:
if (txtUserName.Items.Count > 0)
{
txtUserName.SelectedIndex = 0;
}
Also, you may want to use a different prefix, like "cbo".
Other readers of the code will assume it is a textbox, not a combobox.
Try add comboBox template like this:
<ComboBox Name="txtUserName" IsEditable="True">
<ComboBox.Template>
<ControlTemplate>
<TextBox Text="{Binding Path=/*your property*/}"/>
</ControlTemplate>
</ComboBox.Template>
</ComboBox>

ComboBox.SourceUpdated event is not fired

I have two ComboBoxes on my view. Both of them are bound to two different ObservableCollections in the ViewModel, and when the selected item in ComboBox1 is changed, ComboBox2 gets updated with a different collection. The binding works just fine, however, I want the second ComboBox to always select the first item in its collection. Initially, it works, however, when the source and items in ComboBox2 get updated, the selection index gets changed to -1 (i.e. the first item is no longer selected).
To fix this, I added a SourceUpdated event to ComboBox2 and method that the event calls changes the index back to 0. The problem is that the method is never called (I put a breakpoint at the very top of the method and it doesn't get hit). Here's my XAML code:
<Grid>
<StackPanel DataContext="{StaticResource mainModel}" Orientation="Vertical">
<ComboBox ItemsSource="{Binding Path=FieldList}" DisplayMemberPath="FieldName"
IsSynchronizedWithCurrentItem="True"/>
<ComboBox Name="cmbSelector" Margin="0,10,0,0"
ItemsSource="{Binding Path=CurrentSelectorList, NotifyOnSourceUpdated=True}"
SourceUpdated="cmbSelector_SourceUpdated">
</ComboBox>
</StackPanel>
</Grid>
And in the code-behind:
// This never gets called
private void cmbSelector_SourceUpdated(object sender, DataTransferEventArgs e)
{
if (cmbSelector.HasItems)
{
cmbSelector.SelectedIndex = 0;
}
}
Any help is appreciated.
After working on it for an hour I finally figured it out. The answer is based on this question: Listen to changes of dependency property.
So basically you can define a "Property Changed" event for any DependencyProperty on an object. This can be extremely helpful when you need to extend or add additional events to a control without having to create a new type. The basic procedure is like this:
DependencyPropertyDescriptor descriptor =
DependencyPropertyDescriptor.FromProperty(ComboBox.ItemsSourceProperty, typeof(ComboBox));
descriptor.AddValueChanged(myComboBox, (sender, e) =>
{
myComboBox.SelectedIndex = 0;
});
What this does is that it creates a DependencyPropertyDescriptor object for the ComboBox.ItemsSource property, and then you can use that descriptor to register an event for any control of that type. In this case, every time the ItemsSource property of myComboBox is changed, the SelectedIndex property is set back to 0 (which means the first item in the list is selected.)

Updating the DisplayMember of a ListBox

This question deals with a dinky little Winforms GUI. Let it be known that I have basic knowledge of data bindings and INotifyPropertyChanged and use both in my ViewModels in WPF. But I don't know Winforms. This is for a school assignment.
So I have a class that has a DisplayName property. I also have a ListBox whose Items are a sequence of instances of my class. I have pointed myListBox.DisplayMember = "DisplayName"; After changing a value in an instance of my class that will cause the DisplayName property to return a different value, how do I tell my ListBox to pull the DisplayName property again to refresh its value?
I needed to do the same thing but with a combobox. The workaround I found is to clear and reset the DisplayMember property.
This worked:
myComboBox.DisplayMember = null;
myComboBox.DisplayMember = "DisplayName";
It's important to note that this is perhaps not the best solution as it will cause multiple SelectedValueChanged events but the end result is successful.
Doing it this way probably requires re-binding the listbox, loosing selectedIndex etc.
One workaround is to forget about the DisplayMember property and handle the Format event of the ListBox instead. Something like (from memory) :
// untested
e.Value = (e.Item as MyClass).DisplayValue;
I know this was ages ago but I had similar problem and could not find satisfying solution and finally solved with this single line at the end after updating the values:
bindingsource.EndEdit();
Items on listbox reflects any changes entered into textboxes after Update button clicked. So after lines like this:
textbox1.DataBindings["Text"].WriteValue();
textbox2.DataBindings["Text"].WriteValue();
just insert this line:
bindingsourcevariable.EndEdit();
Hope this helps others who also encounter similar problem but haven't found the right solution
Here is solution code that does everything in XAML as opposed to back end C#. This is how I do my projects utilizing MVVM (minimizing the back end code, and if possible having no back end code)
<ListBox x:Name="lstServers" HorizontalAlignment="Left" Height="285" Margin="20,37,0,0" VerticalAlignment="Top" Width="215"
ItemsSource="{Binding Settings.Servers}"
SelectedItem="{Binding Settings.ManageSelectedServer, Mode=TwoWay}"
DisplayMemberPath="UserFriendlyName"/>
This is a listbox on the Window. The keys to point out here, which can be very tricky, are the usual ItemsSource property being set to a Settings object on my view model, which has a Servers Observable collection.
Servers is a class that has a property called UserFriendlyName.
public sealed class AutoSyncServer : ObservableModel
{
public AutoSyncServer()
{
Port = "80";
UserFriendlyName = "AutoSync Server";
Server = "localhost";
}
private string _userFriendlyName;
public string UserFriendlyName
{
get { return _userFriendlyName;}
set
{
_userFriendlyName = value;
OnPropertyChanged("UserFriendlyName");
}
}
This is a partial code snippet for you of the class itself.
The SelectedItem of the ListBox is bound to an instance of the Selected object that I store in the model view called ManageSelectedServer.
The tricky part here is the DisplayMemberPath is set to "UserFriendlyName" as opposed to "{Binding UserFriendlyName}". This is key
If you use {Binding UserFriendlyName} it will display the UserFriendlyNames in the collection but will not reflect any changes to that property.
The XAML for the TextBox where the user can update the user friendly name (which should change the text in the listbox also) is:
<TextBox x:Name="txtDisplayName" HorizontalAlignment="Left" Height="23" Margin="395,40,0,0" TextWrapping="Wrap"
Text="{Binding ElementName=lstServers,Path=SelectedItem.UserFriendlyName, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Top" Width="240"/>
This sets the Text property of the TextBox and binds it to the ListBox element lstServers SelectedItem property UserFriendlyName. I've also included an UpdateSourceTrigger=PropertyChanged so that any changes made to the text source notify that they have been changed.
XAML is tricky!

Categories