ComboBox itemsSource and default selected value doesn't work - wpf

I have this code:
<ComboBox Name="cbxWorkers" HorizontalContentAlignment="Right"
ItemsSource="{Binding Workers}">
<ComboBoxItem IsSelected="True" Content="Select" />
<ComboBox.ItemTemplate>
<DataTemplate>
<ComboBoxItem Content="{Binding LastName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Everything works fine except the second line.
It gives me a runtime exception:
Items collection must be empty before using ItemsSource.
How can I deal with that so I will get also all the Workers, and also the item - "Select" as the first item of the combobox?
Thanks a lot :)

You can't have two sources. You'd have to specify in code from the ItemsSource which item you want selected.
<ComboBox Name="cbxWorkers" HorizontalContentAlignment="Right" ItemsSource="{Binding Workers}">
<ComboBox.ItemTemplate>
<DataTemplate>
<ComboBoxItem Content="{Binding LastName}" IsSelected="{Binding isSelected}" />
</DataTemplate>
</ComboBox.ItemTemplate>
You can do this, or you can just make an extra first Item in C#/VB and make sure it's selected.

You can do this with a CompositeCollection:
<ComboBox x:Name="cbxWorkers" SelectedIndex="0">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=LastName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem Content="Select" />
<CollectionContainer Collection="{Binding Workers}" />
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
Note: you need to set the SelectedIndex="0" on the ComboBox, because when the ComboBoxItem is in the ItemsSource, its IsSelected property won't set the selection on the ComboBox.
Edit concerning CollectionContainer
As #H.B. pointed out, the Binding on CollectionContainer won't work this way. You have a couple of options. They are spelled out for you by this CodeProject article, so I won't repeat them here. The one method that doesn't mention is the newish (as of .NET 4) x:Reference option. It would be used like this:
<CollectionContainer Collection="{Binding DataContext.Workers, Source={x:Reference cbxWorkers}}" />

Related

WPF ComboBox IsEnable when using custom DataTemplate

Here it's the following. I want to disable a combo box.
In some scenarios in a window I just set SelectedItem from ViewModel to something and don't allowing the user to change it. But in some cases I want to allow.
This one works perfectly when changing ComboBoxIsEnabled property in VM.
<ComboBox ItemsSource="{Binding MyColletionView, Mode=OneWay}"
SelectedItem="{Binding MySelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Name"
IsEnabled="{Binding MyComboBoxIsEnabled}"/>
After changing ComboBox.ItemTemplate the IsEnable property not reacting anymore. In short, I can't disable the ComboBox.
<ComboBox ItemsSource="{Binding MyColletionView, Mode=OneWay}"
SelectedItem="{Binding MySelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding MyComboBoxIsEnabled}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource CustomerConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
I don't want to disable the ComboBoxItem, I want to disable the ComboBox itsef.
Any suggestions, or someone facing the same issue?
<ComboBox Height="20" Width="200" IsEnabled="True" Margin="38,38,1682,1022" ItemsSource="{Binding SourceData}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
I write a sample as you described.but I didnot use mvvm.I want to prove that there is no relationship in IsEnable and ItemTemplate.
you can trace this issue from tips as follow.
Watch Output window in VisualStudio.There may be some exception.
replace mvvm with codebehind and try.

How to select "None" as the first selected item once the combobox is loaded on the UI - WPF

I can't seem to get my combobox to display the "None" item i inserted into my composite collection once the combobox is loaded. If a user decides to change it afterwards, I don't care, but the initial load should set the "None" to be selected first. Here is my XAML
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox DisplayMemberPath="SName" SelectedItem="{Binding BModel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="GId" SelectedValue="{Binding BModel.GId, Mode=TwoWay}"
HorizontalContentAlignment="Stretch"
MinWidth="{Binding ElementName=BAssigned, Path=MinWidth}"
Style="{StaticResource SPanelComboBox}">
<ComboBox.ItemsSource>
<CompositeCollection>
<emodels:SModel SName="None" GId="-1"/>
<CollectionContainer Collection="{Binding DataContext.BListModels,
Source={x:Reference SDataGrid}}"/>
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate >
<DataTemplate>
<ComboBox SelectedItem="{Binding BModel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalContentAlignment="Stretch"
Style="{StaticResource SPanelComboBox}">
<ComboBox.ItemsSource>
<CompositeCollection>
<emodels:SModel SName="None" GId="-1"/>
<CollectionContainer Collection="{Binding DataContext.BListModels,
Source={x:Reference SDataGrid}}"/>
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
Take a look at examples of setting SelectedIndex and SelectedItem in a ComboBox.
<Window.Resources>
<sys:String x:Key="zero">Zero</sys:String>
<spc:StringCollection x:Key="score">
<sys:String>First</sys:String>
<sys:String>Second</sys:String>
<sys:String>Third</sys:String>
</spc:StringCollection>
<CompositeCollection x:Key="strings">
<StaticResource ResourceKey="zero"/>
<CollectionContainer Collection="{Binding Mode=OneWay, Source={StaticResource score}}"/>
</CompositeCollection>
</Window.Resources>
<StackPanel Orientation="Horizontal">
<!--Only index specified-->
<ComboBox Width="100" VerticalAlignment="Top"
ItemsSource="{Binding Mode=OneWay, Source={StaticResource strings}}"
SelectedIndex="0" />
<!--Only SelectedItem set-->
<ComboBox Width="100" VerticalAlignment="Top"
ItemsSource="{Binding Mode=OneWay, Source={StaticResource strings}}"
SelectedItem="First" />
<!--SelectedIndex and SelectedItem set to the same item-->
<ComboBox Width="100" VerticalAlignment="Top"
ItemsSource="{Binding Mode=OneWay, Source={StaticResource strings}}"
SelectedIndex="0"
SelectedItem="Zero" />
<!--SelectedIndex and SelectedItem set to different items-->
<ComboBox Width="100" VerticalAlignment="Top"
ItemsSource="{Binding Mode=OneWay, Source={StaticResource strings}}"
SelectedIndex="0"
SelectedItem="First" />
</StackPanel>
The example shows that SelectedItem has a higher priority than SelectedIndex. And if both properties are set then SelectedItem will be used.
In your code, the BModel property contains an item from the BListModels collection or is null.
And using SelectedIndex = 0 you want to set the SelectedItem to SName = "None".
Since SelectedItem has a different meaning, setting SelectedIndex = 0 will be ignored.
I see two solutions.
The first is when initializing the BModel property to set its value to non-null, but SName = "None".
I cannot show you how to do this.
Since you haven't given enough code, I need to see how you have implemented the BListModels, emodels: SModel collection types, of an element that has a BModel property.
The second variant is to set the SelectedIndex value AFTER the ComboBox is loaded.
I'll show you an variant here using C # code, but you can also implement it using AP property, Behavior, or whatever.
<StackPanel>
<ComboBox Width="100" VerticalAlignment="Top"
ItemsSource="{Binding Mode=OneWay, Source={StaticResource strings}}"
SelectedIndex="0"
SelectedItem="First" Loaded="ComboBox_Loaded" />
<x:Code>
<![CDATA[
private void ComboBox_Loaded(object sender, RoutedEventArgs e)
{
((Selector)sender).SelectedIndex = 0;
}
]]>
</x:Code>
</StackPanel>

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}">

Default item in bound ComboBox

I have a bound ComboBox where I need to show default item "No Selection". ComboBox should close with no text selection and no selected item, When the user selects this option ("No Selection") from list.
These are the data resources
<UserControl.Resources>
<my:iTimeKeepBaseDataSet x:Key="iTimeKeepBaseDataSet" />
<CollectionViewSource x:Key="codeSetsViewSource" Source="{Binding Path=codeSets, Source={StaticResource iTimeKeepBaseDataSet}}" />
<CollectionViewSource x:Key="allMattersViewSource" Source="{Binding Path=allMatters, Source={StaticResource iTimeKeepBaseDataSet}}" />
<my:CodeIdToDetailsConverter x:Key="codeIdDetailsConverter" />
</UserControl.Resources>
This is ComboBox data template
<DataTemplate x:Key="CodeSetDataCellEditTemplate">
<ComboBox DataContext="{StaticResource codeSetsViewSource}"
ItemsSource="{Binding}"
SelectedValuePath="{Binding Path=codeSetId}"
SelectionChanged="OnCodeSetsSelectionChanged"
Style="{StaticResource ComboboxTemplate}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} - {1}">
<Binding Path="codeSetId" />
<Binding Path="codeSetName" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
Template column of DataGrid
<DataGridTemplateColumn x:Name="codeSetId1Column"
Width="SizeToHeader"
CellEditingTemplate="{StaticResource CodeSetDataCellEditTemplate}"
Header="Code Set ID 1"
my:DataGridAttachedProperty.ColumnName="codeSetId1">
Please suggest me a solution for this.
Thanks in advance
You can use CompositeCollection
<CompositeCollection>
<ComboBoxItem IsEnabled="False" Foreground="Black">Select Item</ComboBoxItem>
<CollectionContainer Collection="{Binding Source={StaticResource DataKey}}" />
</CompositeCollection>
But, you can't use Binding here, workaround is to use BindingProxy with CompositeCollection
See my answer here and comments for more details

How to trigger DataGridevents DataGridBeginningEdit, DataGridCellEditEnding with a Combobox in Silverlight? / CellTemplate for a Combobox

I want to use the DataGridevents (DataGridBeginningEdit, DataGridCellEditEnding, ..etc) to handle and detect changes. As far as I understood, without a "CellTemplate" these are not triggered. So I am trying to create an appropriate celltemplate using a TextBlock, but I guess it is not very straightforward with the binding I am using for the Combobox in the CellEditingTemplate, because I am using "DisplayMemberPath"..
There are examples of simpler cases but I couldn't find smth for this scenario. See Xaml snippet below;
<data:DataGridTemplateColumn Width="100">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Center" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox HorizontalAlignment="Stretch"
ItemsSource="{Binding DurationTypeList, Source={StaticResource itemSourceProvider}}"
SelectedValuePath="Code"
SelectedValue="{Binding Path=DurationTypeCode, Mode=TwoWay}"
DisplayMemberPath="Template" />
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
</data:DataGridTemplateColumn>
Thank you
It turns out, i have two options..
Solution #1
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Left" Text="{Binding Path=DurationType.Template, Mode=OneWay}" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox HorizontalAlignment="Stretch"
ItemsSource="{Binding DurationTypeList, Source={StaticResource itemSourceProvider}}"
SelectedValuePath="Code"
SelectedValue="{Binding Path=DurationType, Mode=TwoWay}"
DisplayMemberPath="Template" />
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
I changed the binding path from string to the object with Code and Template properties..
This blog helped a lot..

Resources