I am trying to bind a ComboBox to a Field that is in a DataGrid and am unable to get it to update.
Here is the ComboBox from the xaml:
<ComboBox Grid.Row="6" Grid.Column="1" x:Name="cmbBedArea" HorizontalAlignment="Left" VerticalAlignment="Center" SelectedValue="{Binding ElementName=gridUsers, Path=SelectedValue.BedArea, Mode=OneTime}" Width="200"/>
Here is the full xaml file:
<Window x:Class="WinPharm.Net.frmDbUsers"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WinPharm.Net"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Title="WinPharm User Management" Height="450" Width="800">
<Window.Resources>
<Style x:Key="spacerRow" TargetType="RowDefinition">
<Setter Property="Height" Value="10"/>
</Style>
</Window.Resources>
<Grid>
<!--Users Grid-->
<DataGrid
x:Name="gridUsers"
VerticalAlignment="Top"
Height="150"
Margin="10,10,10,0"
IsReadOnly="True"
AutoGenerateColumns="False"
GridLinesVisibility="All"
AlternatingRowBackground="LightGray"
SelectionMode="Single"
SelectionUnit="FullRow"
Loaded="gridUsers_Loaded"
SelectionChanged="gridUsers_SelectionChanged"
>
<DataGrid.Columns>
<DataGridTextColumn Header="" Width="20"/>
<DataGridTextColumn x:Name="LoginId" Header="Id" Width="150" Binding="{Binding LoginID}"/>
<DataGridTextColumn x:Name="Name" Header="Name" Width="200" Binding="{Binding Name}"/>
<DataGridTextColumn x:Name="BedArea" Header="Bed Area" Width="200" Binding="{Binding BedArea}" />
</DataGrid.Columns>
</DataGrid>
<!--Form Fields-->
<Grid Margin="10,175,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Height="Auto" Width="400">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Style="{StaticResource spacerRow}"></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition Style="{StaticResource spacerRow}"></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition Style="{StaticResource spacerRow}"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition Width="280"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Login Id:" HorizontalAlignment="Right" VerticalAlignment="Top"/>
<TextBox IsEnabled="False" Grid.Row="0" Grid.Column="1" x:Name="txtLoginId" HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding ElementName=gridUsers, Path=SelectedItem.LoginID}" Width="200" MaxLength="50"/>
<Label Grid.Row="2" Grid.Column="0" Content="Name:" HorizontalAlignment="Right" VerticalAlignment="Top"/>
<TextBox Grid.Row="2" Grid.Column="1" x:Name="txtName" HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding ElementName=gridUsers, Path=SelectedItem.Name, Mode=OneWay}" Width="200" MaxLength="50"/>
<Label Grid.Row="4" Grid.Column="0" Content="External Id:" HorizontalAlignment="Right" VerticalAlignment="Top"/>
<TextBox Grid.Row="4" Grid.Column="1" x:Name="txtExternalId" HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding ElementName=gridUsers, Path=SelectedItem.ID_External, Mode=OneWay}" Width="200" MaxLength="50"/>
<Label Grid.Row="6" Grid.Column="0" Content="Bed Area:" HorizontalAlignment="Right" VerticalAlignment="Top"/>
<ComboBox Grid.Row="6" Grid.Column="1" x:Name="cmbBedArea" HorizontalAlignment="Left" VerticalAlignment="Center" SelectedValue="{Binding ElementName=gridUsers, Path=SelectedValue.BedArea, Mode=OneTime}" Width="200"/>
</Grid>
<!--Form Buttons-->
<Grid HorizontalAlignment="Center" VerticalAlignment="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"></ColumnDefinition>
<ColumnDefinition Width="120"></ColumnDefinition>
<ColumnDefinition Width="120"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button x:Name="btnAdd" Grid.Column="0" Content="Add" Height="40" Width="100" Margin="10,0,0,10" Click="btnAdd_Click"></Button>
<Button x:Name="btnDelete" Grid.Column="1" Content="Delete" Height="40" Width="100" Margin="10,0,0,10" Click="btnDelete_Click"></Button>
<Button x:Name="btnUpdate" Grid.Column="2" Content="Update" Height="40" Width="100" Margin="10,0,0,10" Click="btnUpdate_Click"></Button>
</Grid>
</Grid>
</Window>
Any idea why the ComboBox does not get updated?
I put this into the code behind and was able to get it updating, but would like to do so without this code.
private void gridUsers_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var drv = ((DataRowView)((DataGrid)sender).SelectedItem).Row;
if (drv != null)
{
cmbBedArea.SelectedValue = drv["BedArea"];
}
}
Maybe you confuse BindingMode.OneTime
with BindingMode.OneWay
.
BindingMode.OneTime
means the binding will read the binding source just one time (hence the name of the binding mode). Any following updates of the data source will be ignored.
BindingMode.OneWay
on the other hand will track any binding source changes for the lifetime of the Binding
object.
BindingMode.OneTime
is only used when you don't expect the data source to change (or you are only interested in the initial value). This will improve the application's performance as the binding engine does not need to monitor the binding source in order to detect changes.
"I am also unclear why the default mode works and the OneTime does not."
The default binding mode of the ComboBox.SelectedValue
property is BindingMode.TwoWay
- that's why the default works. It updates binding source and target (two way. The majority of dependency properties default to BindingMode.OneWay
).
At this point you should have understood that BindingMode.OneTime
will allow the target (ComboBox
) to update only once - a one time binding.
"however I would prefer that the grid does not get updated upon change of the ComboBox."
In this case you must change the Binding.Mode
property explicitly to BindingMode.OneWay
. This way the ComboBox
will only receive changes but won't send changes. Remember, the default for the SelectedValue
property is BindingMode.TwoWay
which will of course allow the ComboBox
to update the DataGrid
.
BindingMode.OneWay
is your configuration value.
<!-- Unless you also define the 'SelectedValuePath'
you should use the 'SelectedItem' property instead of 'SelectedValue' -->
<ComboBox SelectedItem="{Binding Mode=OneWay, Path=SelectedItem.BedArea, ElementName=gridUsers}" />
<!-- Alternative version using 'SelectedValuePath' and 'SelectedValue'-->
<ComboBox SelectedItem="{Binding Mode=OneWay, Path=SelectedValue, ElementName=gridUsers}" />
<DataGrid x:Name="gridUsers"
SelectedValuePath="BedArea" />
In general, if you want updates (binding target and/or binding source): set Binding.Mode
to BindingMode.OneWay
, BindingMode.TwoWay
or BindingMode.OneWayToSource
.
No updates: BindingMode.OneTime
.
See BindingMode
.