WPF Combobox with view source and dropdown source - wpf

I am sure others have done this but I can't find any examples or I just don't know how to word it.
WPF Combobox with EmployeeID as valueMember and EmployeeName as DisplayMember. EmployeeID is saved to the table as ApprovedByID.
Let's say I have a WPF Combobox for a field that holds the employee id of somebody who approved a purchase. I don't want the list filtered for displaying the name, but when it comes to changing the employee, I want to filter the items in the dropdown to only be current employees.
The goal, on old records, shows who approved it. On new records or when editing an old record, I only want current employees selected. I've done this before in Winforms but that was long ago and I forgot :(
Can this be done with a WPF Combobox or do I need to create a control with a TextBlock for display and a Listbox as the dropdown?
<ComboBox Grid.Row ="5" Grid.Column="1" Margin="10, 2"
Attached:ComboBoxAttached.AllowNull="True"
Style="{StaticResource ComboBoxFlatStyle}"
ItemsSource="{Binding Employees}"
IsEnabled="{Binding Edit}"
DisplayMemberPath="FullName"
SelectedValuePath="ID" SelectedValue="{Binding
Current.APPROVED_BY_ID}" />

Related

Which tool is the best option for doing search in Datagrid in wpf?

I have created search option using combobox, for example
In combobox1 items are m1,m2,m3,m4,m5 based on that, if m1 item selected then
another combobox2 displays with items a,b,c,d and if a item is selected another
combobox3 dispalys, based on last combobox it searches on the datagrid.
I think it is long process, use of many combobox makes it lenghty. Is any
other way is their to implement this. plz help
<ComboBox Grid.Column="1"
Grid.Row="1"
x:Name="cmbType"
VerticalAlignment="Top"
IsEnabled="{Binding IsOther}"
ItemsSource="{Binding Source={StaticResource enumTypeOfType}}"
SelectedItem="{Binding SearchType,Mode=TwoWay}"
SelectedIndex="{Binding CmdResIndex,Mode=TwoWay}"
IsSynchronizedWithCurrentItem="True"
SelectionChanged="DataSource1"
Margin="0,0,1,0">
</ComboBox>
So if i get this right, you have a collection a, which goes to collection b,etc, and the second collection will change based on the selected item of the first? You have to remember, that since the data will change for each selection, hard coding the value is out of the question.
Knowing this, WPF provides you with a great mechanism for this. Using a stackpanel, with a list view will actually work.
<ItemsControl ItemsSource="{binding collections}" ItemTemplate="{binding TemplateForListViewItems}" ItemPanelTemplate="{binding itemPanelTemplate}"></ItemsControl>
Now, with the items control, one can simply set an ItemTemplate/DataTemplate, to set the styling of each control. Linking to the onclick event, or using interactions, you can simply do collections.Add to add your new list view with generated data for the selection, and done.

Bind datagrid to one ViewModel, column / combobox to another

I a have a View Players, the datacontext is set to a ObservableCollection Players from the ViewModel MainPlayerViewModel.
In the View I have a datagrid with columns TeamId, Name and Position.
I want to bind the TeamId column with a combobox to a list of available teams from the MainTeamViewModel which has a collection property Teams but of course I want the MainPlayerViewModel to be updated whenever I update the team for a player.
I hope you can follow me here..
This is my xaml:
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox DataContext="{Binding MainTeam, Mode=OneWay, Source={StaticResource Locator}}"
Height="23" HorizontalAlignment="Left"
Name="cmbTeams" VerticalAlignment="Top" Width="100" ItemsSource="{Binding Teams,
Mode=TwoWay}" SelectedValue="{Binding Path=Model.teamid, Mode=TwoWay}"
DisplayMemberPath="Model.teamid"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
When I edit the cell it shows the list of available teams but the selectedvalue I pick from the list doesn't turn up in the TeamId column
How do I pull this off?
Kind regards,
Mike
UPDATE:
Despite the help I received I didn't get it to work binding one View to 2 different Viewmodels.
Guess the solution offered is long above my head..
I couldn't set the datacontext of the datagrid to MainTeam because it has an ItemsSource of players and a selecteditem bound twoway to selectedplayer.
Anyway I decided to keep it 1 View / 1 ViewModel and created a public property on my PlayerViewModel named teamsVM:
public MainTeamViewModel teamsVM
{
get
{
return ViewModelLocator.Container.Resolve<MainTeamViewModel>();
}
}
Now I can set the Itemsource to this new property and my player row get's updated when I change teams:
<DataTemplate>
<ComboBox
Height="23" HorizontalAlignment="Left"
Name="cmbTeams" VerticalAlignment="Top" Width="100"
ItemsSource="{Binding teamsVM.Teams,
Mode=TwoWay}" SelectedValue="{Binding Model.teamid, Mode=TwoWay}"
DisplayMemberPath="Model.teamid" SelectedValuePath="Model.teamid"/>
</DataTemplate>
Regards,
Mike
I find two things wrong with this code.
You are missing the SelectedValuePath for the ComboBox. Even though you bind all teams to it, the selected item's id is null because the SelectedValuePath is missing.
You also have a DataContext and an ItemsSource. Use only the ItemsSource for the teams you want to display, and the SelectedValue to be bound to the player's teamId, unless your view model has a "Teams" property and a "Player" property, in which case the DataContext may be used. (Id set the DataContext in code though...)
So yo will end up with something like this:
ItemsSource="{Binding Teams, Mode=TwoWay}" //Bind to all teams.
SelectedValue="{Binding Player, Path=TeamId, Mode=TwoWay}" //Bind to the teamId of the player.
DisplayMemberPath="TeamName" //that's the Name of each team.
SelectedValuePath="TeamId" //that's the Id of the team.
Two problems here:
First, as #bleepzer noted you did not specify the value/display paths in your combo box.
Second, you trying to access a property in the data context that is outside your grid (i.e. the main view model's data context) from within a data template. In silverlight 4 there is no relative source binding (something you would use in SL 5 or WPF), so you will have to use element binding to archive what you want.
Here is an example based on your code. It is not complete as it leaves out some of the DataGrid elements needed, but it shows the concept:
<data:DataGrid x:Name="myDataGrid"
DataContext="{Binding MainTeam, Mode=OneWay, Source={StaticResource Locator}}" >
<!-- additional stuff needed here -->
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Height="23" HorizontalAlignment="Left"
Name="cmbTeams" VerticalAlignment="Top" Width="100"
ItemsSource="{Binding ElementName=myDataGrid, Path=DataContext.Teams}"
SelectedValuePath="TeamId"
DisplayMemberPath="TeamName"
SelectedValue="{Binding Path=Model.teamid, Mode=TwoWay}"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
<!-- additional stuff needed here -->
<data:DataGrid>
And here is the description:
Add a name to your data grid.
Make sure the data grid has the right data context, either by setting it explicitly as in the sample, or inheriting it from the parent hierarchy.
Modify your ComboBox's ItemsSource property to point to the data grid using the element name you specified earlier. As you are now on the element and not on the data context you have to use DataContex.Teams to access the Teams property on the data context of your grid. The ItemsSource does not need two-way-binding as the view does not write anything back to your view model.
Specify the SelectedValuePath and DisplayMemberPath properties.
Finally, bind the SelectedValue property of the combo box to your rows model TeamId property using two-way-binding - needed now as the view should update the model's value. Important: the SelectedValue property of the combo box has to be bound after the ItemsSource to prevent some problems with the combo box.

Bind Combobox with huge data in WPF

I am trying to bind combobox with custom object list. My object list have around 15K record and combobox takes long time to show the data after clicking on combobox.
Below are the code:
<ComboBox Height="23" Name="comboBox1" Width="120" DisplayMemberPath="EmpName" SelectedValue="EmpID" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"/>
code behind:
List<EmployeeBE> allEmployee = new List<EmployeeBE>();
allEmployee = EmployeeBO.GetEmployeeAll();
comboBox1.ItemsSource = allEmployee;
allEmployee have around 15K record.
Can any one Suggest how can I improve my combobox performance?
That's bad UI design: No user will read through 15K records.
You can improve the performance by allowing the user to enter some filter criteria before showing the results, for example, by using an AutoCompleteBox instead of a ComboBox.
You could try a VirtualizingStackPanel as described here - http://vbcity.com/blogs/xtab/archive/2009/12/15/wpf-using-a-virtualizingstackpanel-to-improve-combobox-performance.aspx
As others have said, you really want to re-imagine your UI, as a ComboBox isn't appropriate for 15k records.
Try using a VirtualizingStackPanel as ItemsPanel for the ComboBox.
<ItemsPanelTemplate x:Key="ComboBoxItemsPanelTemplate">
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
<ComboBox ItemsPanel="{StaticResource ItemsTemplate}"/>

WPF binding to individual 'rows' (not columns) of a datagrid possible?

I have a datagrid. A column of the datagrid is a simple <DataGridTemplateColumn> with its CellTemplate containing a <DataTemplate> which contains a <ComboBox> such as
<my:DataGrid Name="dataGridMain" AutoGenerateColumns="False">
<my:DataGrid.Columns>
<my:DataGridTemplateColumn Header="Food" >
<my:DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<ComboBox Name="comboDataTemplate"
Text="{Binding Path=Food,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding Source={StaticResource resFoodLookups}}"
DisplayMemberPath="FoodName"
SelectedValuePath="FoodID" IsEditable="True" />
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
</my:DataGridTemplateColumn>
</my:DataGrid.Columns>
</my:DataGrid>
All is working fine. Each combobox is bound to a static list due to the ItemsSource="{Binding Source={StaticResource resFoodLookups}}" statement.
But my requirement is that this list will change from row-to-row.
That is: each time a user types a new entry in the combobox list on one row, I want to have it available in the selection on the next row.
Basically, I want to create a new list for the user each time the user inserts a new word in the combobox on any of the rows. (The combobox is editable).
Now, I can wire up the "ItemsSource=..." at run-time, but I'm only able to do this once thus the <DataTemplate> propagates the 'same' list to 'all' the comboboxes on 'all' the rows.
My thoughts are that I need to change the ItemsSource=... property on an object-by-object basis on each combobox that is created in memory after the DataTemplate has created them - but I have no idea how to do this.
What you need to do is perform 2 way data binding to your the ItemsSource, this way when the ItemSource is updated in one of the combo boxes it will auto update your original collection and therefore your other combo boxes as well.
What I normally do is use the MVVM pattern. It is worth some research if you are not already using a particular pattern on your application.
Using it to solve your problem i would do the following:
Create a ViewModel (Lets call it MyViewModel) which has a collection of values called 'MyComboBoxItems' (It is important that you use ObservableCollection for the databinding to work)
When I create the Window/Control that contains your table, I also create an instance of MyViewModel and set its the Window.DataContext=myViewModelInstance
For your combobox binding use ItemsSource="{Binding Path=MyComboBoxItems, Mode=TwoWay}

DataGridComboBoxColumn is empty if text does not exist in the dropdown

I am using the WPF Toolkit DataGrid bound to Person collection. The LastName is represented by the ComboBox with wellknown names.
<x:Array x:Key="knownLastNames" Type="sys:String">
<sys:String>Johnson</sys:String>
<sys:String>Williams</sys:String>
</x:Array>
The problem is that if I set LastName to "Brown" (missed in knownLastNames), the ComboBox column is empty.
<dg:DataGridComboBoxColumn Header="LastName" TextBinding="{Binding LastName}" ItemsSource="{Binding Source={StaticResource knownLastNames}}" />
If I make the ComboBox editable, I can see "Brown", but only when in edit mode (pressed F2).
This is a bug that I have already raised in the forums and confirmed via email with Vincent (a coordinator on the project). I ended up writing my own custom column type just so I could do editable ComboBoxes.

Resources