Silverlight ComboBox SelectionChanged event fires twice - silverlight

I'm using a ComboBox within a DataGrid. I am using this DataGrid for both "Add" and "Edit". When I change the value of ComboBox in code during "Edit", the SelectionChanged Event gets fired twice. 1st time it assigns the proper value, then 2nd time null is assigned to ComboBox which clears the data I had set previously!!
I can't figure out what exactly I'm doing wrong.
Here's the XAML snippet where I bind the ComboBox to model.
<sdk:DataGridTextColumn x:Name="SlNo" Binding="{Binding SlNo}" Header="sl.no" IsReadOnly="True"/>
<sdk:DataGridTemplateColumn Header="Activity Type">
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox x:Name="ActivityTypeCombo" IsDropDownOpen="True"
ItemsSource="{Binding AvailableActivityTypes}"
SelectionChanged="ActivityTypeSelectionChanged"
SelectedItem="{Binding SelectedActivityType, Mode=TwoWay}"
SelectedValue="{Binding Path=Description, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Description}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
The Code Snippet where I set the value is:
foreach (var claimDetailViewModel in Claims)
{
claimDetailViewModel.SelectedActivityType =
_autoFillModel.ActivityTypes.SingleOrDefault(at => at.Id == climDetailViewModel.ActivityTypeId);
}
ClaimDetailsGrid.ItemsSource = Claims;

It seems to me that using both SelectedItem and SelectedValue to control selection will not work properly.
When SelectedItem is set this will most likely trigger SelectedValue to be evaluated, and because there is no SelectedValuePath set it will result in SelectedItem=null.
Try removing the SelectedValue binding.

Related

Binding Textblock text inside a combobox grid cell

I'm using a combobox cell inside a datagridview through datatemplate.
I bind an item source and set the DisplayMemberPath , SelectedValuePath and SelectedValue proprieties on the combobox inside
Once a item in the combobox is selected I would like to show the DisplayMemberPath text on the textblock element, I just don't know how to bind it.
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding Path=DataContext.PartNumbers, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
DisplayMemberPath="PartNumberDescription"
SelectedValuePath="PartNumberCodeCode"
SelectedValue="{Binding Code}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{How can I bind DisplayMemberPath here?}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
If I use the same bind of SelectedValue, it works and the value is displayed, but I would like to show the description.
<TextBlock Text="{Binding Code}"/>
<!-- It works, but I would like to show the text of the combobox, not the value -->
XAML
<TextBlock Text="{Binding Description}"/>
ViewModel
public string Description {
get {
return PartNumbers.SingleOrDefault(x => x.PartNumberCodeCode == Code)?.PartNumberDescription;
}
}
On property change of Code, notify property change of Description

Silverlight control updates binded property when it should not

I have a custom control in datagrid DataGridTemplateColumn.CellEditingTemplate:
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Path=Items}">
<DataGrid.Columns>
<data:DataGridTemplateColumn Header="Column1" >
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<sdk:Label Content="{Binding Path=Description}"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<common:MyControl SelectedObject="{Binding Path=SelectedItem, Mode=TwoWay, UpdateSourceTrigger=Explicit}"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
</data:DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Inside of control I have exactly one place where I update SelectedObject dependency property:
BindingExpression expressionObject = GetBindingExpression(SelectedObjectProperty);
if (expressionObject != null)
{
expressionObject.UpdateSource();
}
This code is called on the LostFocus event.
Problem is: while UpdateSource method is called only once (checked with debugger) SelectedItem gets updated value(same) twice! I'm currently in loss since it's not supposed to be this way. Am I missing something?
Edit: I'm not using any MVVM framework. VS2012 debug callstack shows that first update is initiated by UpdateSource() call, but second just comes out of nowhere.

SelectedItem is null in DataGridTemplateColumn with ComboBox

I have a Datagrid and DataGridTemplateColumn which is ComboBox
<DataTemplate x:Key="ComboBoxPackagingType">
<ComboBox SelectedItem="{Binding PackagingType.SelectedItem, Mode=TwoWay}" ItemsSource="{Binding PackagingType.ItemsSource}"/>
</DataTemplate>
...
<DataGridTemplateColumn CellTemplate="{StaticResource ComboBoxPackagingType}"/>
The SelectedItem is never changing the value after selecting an Item from list.
I set the breakpoints on both get and set functions and it is stopping on get function after changing the ItemSource of my DataGrid but never on the set function after selecting an Item from list.
Why?
Try adding UpdateSourceTrigger=PropertyChanged to the binding of your ComboBox's selected item like so:
<DataTemplate x:Key="ComboBoxPackagingType">
<ComboBox SelectedItem="{Binding PackagingType.SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding PackagingType.ItemsSource}"/>
</DataTemplate>
This worked for me.

binding combox in wpf datagrid

I have a list that I populate in the init of my viewmodel:
ListOfEmployees = new List<EmployeeBO>(employeeRepository.GetEmployees(true, true));
I am trying to get a combobox in a datagrid to populate from this list.
<DataGridTemplateColumn Header="U/M" MinWidth="145">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Name="cboUnitMeasure"
ItemsSource="{Binding Path=ListOfUnitMeasures}"
DisplayMemberPath="UnitMeasureDescription" SelectedValuePath="UnitMeasureValue"
SelectedValue="{Binding UnitMeasureValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Left" Width="140" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding UnitMeasureDescription}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
When the dg loads, the cell template displays the UnitMeasureDescription value, but when I click on the cell to edit, there are no items in the combobox. On the other hand, when I use a static resource from an xml file as the itemsource-using the same property names-the combobox contains the items:
<DataGridTemplateColumn Header="U/M" MinWidth="145">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Name="cboUnitMeasure"
ItemsSource="{Binding Source={StaticResource UnitMeasureData}}"
DisplayMemberPath="UnitMeasureDescription" SelectedValuePath="UnitMeasureValue"
SelectedValue="{Binding UnitMeasureValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Left" Width="140" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding UnitMeasureDescription}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I put a breakpoint just after populating ListOfEmployees in my vm and it contains items. I also verified the property names in the DisplayMemberPath and SelectedValuePath are correct. Not sure what I am doing wrong here.
Is "ListOfUnitMeasures" a property on the VM or a property of an EmployeeBO? Ok, assuming that the DataGrid's ItemsSource is set to the List<EmployeeBO> and that there's another list on the VM called "ListUnitOfMeasures", here's my explanation:
The DataContext of each row in the DataGrid will be equal to the elements in the DataGrid's ItemsSource. In your case, each row will use an EmployeeBO as its DataContext. And since the "ListOfUnitMeasures" isn't a property of Employee BO, the Binding on the ComboBox will not work and thus won't display anything.
One possible solution is change the Binding on your ComboBox to use a RelativeSource pointing back to the parent DataGrid as follows:
<ComboBox Name="cboUnitMeasure"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.ListOfUnitMeasures}"/>

Why is this WPF ComboBox not showing the selected value?

<CombobBox x:Name="cbo"
Style="{StaticResource ComboStyle1}"
DisplayMemberPath="NAME"
SelectedItem="{Binding Path=NAME}"
SelectedIndex="1">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=NAME}"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
In the Window OnLoaded event, I wrote the code to set the ItemsSource:
cbo.ItemsSource = ser.GetCity().DefaultView;
While loading the window I can see that the initially the the first item is loading but at the same time it clears the displayed item. I am stuck in this scenario and any help is appreciated.
Regards
Kishore
QUICK ANSWER : Set SelectedIndex = 1 from code-behind.
It seems that the code in XAML executes first (the InitializeComponent() method), which sets SelectedIndex = 1, but ItemsSource is not specified yet! So SelectedIndex won't affect! (And remember, you cannot specify ItemsSource before InitializeComponent())
So you have to manually set SelectedIndex = 1 after setting ItemsSource.
You should do like this :
XAML
<ComboBox x:Name="cbo"
Style="{StaticResource ComboStyle1}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=NAME}"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Code
cbo.ItemsSource = ser.GetCity().DefaultView;
cbo.SelectedIndex = 1;
Or this:
XAML
<ComboBox x:Name="cbo" Initialized="cbo_Initialized"
Style="{StaticResource ComboStyle1}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=NAME}"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Code
private void cbo_Initialized(object sender, EventArgs e)
{
cbo.SelectedIndex = 1;
}
Also note that i've removed DisplayMemberPath="NAME" because you cannot set both DisplayMemberPath and ItemTemplate at the same time. And also, use either SelectedItem or SelectedIndex, not both.
Resetting the ItemsSource will mess up the selection.
Also, you are setting both SelectedItem and SelectedIndex. You want to set only one of these; if you set both, only one will take effect.
In addition, your SelectedItem declaration is probably wrong. SelectedItem="{Binding NAME}" will look for an item which is equal to the value of the NAME property of the ambient (probably Window-level) DataContext. This will work only if the ComboBox.ItemsSource is a list of strings. Since your ItemTemplate works, I assume ComboBox.ItemsSource is actually a list of City objects. But you are telling WPF that the SelectedItem should be a string (a NAME). This string will never be equal to any City object, so the result will be no selection.
So to fix the problem, after setting ItemsSource, set either SelectedItem or SelectedIndex, depending on your requirements and your data model:
cbo.ItemsSource = ser.GetCity().DefaultView;
cbo.SelectedIndex = 1;
// or: cbo.SelectedItem = "Wellington"; // if GetCity() returns strings - probably not
// or: cbo.SelectedItem = City.Wellington; // if GetCity() returns City objects

Resources