WPF DataGrid Radio Button Binding Issue - wpf

I am having RadioButton binding issue.Below is my xaml code.
<Grid Style="{DynamicResource MainFrameGrid1}">
<Grid Name="grdPCM">
<DataGrid AutoGenerateColumns="False" Height="407" HorizontalAlignment="Left" Margin="18,102,0,0" Name="dgMI" VerticalAlignment="Top" Width="781"
CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeColumns="True" CanUserSortColumns="False" SelectionMode="Single"
SelectionUnit="Cell" EnableColumnVirtualization="True">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<RadioButton Name="rbM" GroupName="CMGrp" IsChecked="{Binding Path=SELECT, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Grid>
In code behind I am doing like this.
I am getting data from the database and storing it in the DataTable "dtMIData".Then I am temporarily adding a boolean column called "SELECT" and assigning it to data grid like below in code behind.
DataColumn dcRB = new DataColumn("SELECT");
dcRB.DataType = Type.GetType("System.Boolean");
dcRB.DefaultValue = false;
dtMIData.Columns.Add(dcRB);
dtMIData.AcceptChanges();
dgMI.ItemsSource = dtMIData.AsDataView();
I am binding this new column "SELECT" with the RadioButton control.I want to select only one record,out of multiple retrieved records and want to retrieve the selected record in the code behind based on the "SELECT" column value.i.e."SELECT" column value is true.But even though RadioButton is checked,required binding column "SELECT" is not updating with value true.How to reflect the checked state in the related binding column?

In a DataGrid the bindings do not get updated until you end editing of the row. Try adding UpdateSourceTrigger=PropertyChanged to the RadioButton's binding expression to update bindings immediately:
<RadioButton Name="rbM" GroupName="CMGrp" IsChecked="{Binding Path=SELECT, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

Related

ComboBox items with a binded value

In my WPF page I would like to create a ComboBox with first item empty and the second one binded with a property value, so I did:
<DataGrid x:Name="grdTmplBit" ColumnWidth="*" Style="{StaticResource DataGridStyle}" EnableColumnVirtualization="True" CanUserSortColumns="true" Margin="4,3,2,7" MaxHeight="930" SelectionMode="Extended" SelectionUnit="FullRow" ItemsSource="{Binding ElementName=ObjectsTree, Path=SelectedItem.InfosView, IsAsync=True}" >
<DataGrid.Columns>
<DataGridTemplateColumn Width="110" Header="COMM" Visibility="Visibile">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Width="90" SelectedValue="{Binding Comm.UnitName, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource workModeStyle}" SelectedValuePath="Content">
<ComboBoxItem Content="" />
<ComboBoxItem Content="{Binding Comm.UnitName}" />
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
The property UnitName is a string. Please consider that the ComboBox is inside a DataGridTemplateColumn. Basically the second item is always empty and if I change the ComboBox with a TextBox the value are shown correctly. Any help?
I think your issue is that you bind the SelectedValue to Comm.UnitName and you also bind the second ComboBoxItem content to this property. This means the ComboBox will act in one of these ways:
(Initial selected value is from Comm.UnitName) > The selected line shows this item> You select the empty item > The Comm.UnitName will get set to the empty string > Result: Both ComboBoxItems are empty (one is set as empty, the other is synchronized with Comm.UnitName, which is empty now, too)
(Initial selected value is the first item, empty) > The selected line shows this item > The Comm.UnitName will get set to the empty string > Result: The same as above.
In order to solve this issue, you could consider one of these options:
Create a dedicated property for the SelectedValue, so the Comm.UnitName does not get overwritten.
Create a dedicated property for the value in the ComboBoxItem.
Use a OneTime mode binding to only synchronize the initial value (this does not work for all cases, especially not if you save the empty value in Comm.UnitName, same issue).
<ComboBoxItem Content="{Binding Comm.UnitName, Mode=OneTime}" />

WPF Databinding Link Textblock text to Combobox Selection

I have this xaml in my datagrid:
<DataGridTemplateColumn Header="Status" Width="*" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="StatusText" Text="{Binding Description}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox
ItemsSource="{Binding Source={StaticResource StatusItems}}"
SelectedValue="{Binding Status, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}"
DisplayMemberPath="Description"
SelectedValuePath="Status"
x:Name="Combo"
/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
When i change the value of the combobox, the dataset updates perfectly, but the textblock text doesn't update to the new value I have to refill the entire dataset for the textblock to match the newly selected combobox value. I see the correct method is to implement INotifyPropertyChanged, but that would require significant changes to the way the app fills the dataset, at least from what i understand reading similar posts. I don't have a model that i can implement on, i'm wondering if i can simply set a trigger on the textblock that will change the value whenever the combobox selection changes.
Here is how i am filling the datagrid, if someone knows how i can modify this to implement INotifyPropertyChanged, that would also be great, but i don't think that will work without a model defined (again, just going on what i see others doing).
Dim con As New SqlConnection(str)
Dim ds As New DataSet()
Dim Adpt As New SqlDataAdapter
Adpt.SelectCommand = New SqlCommand(com, con)
con.Open()
Adpt.Fill(ds, "dbo.tmfCNCComponent_threed")
dataGrid1.ItemsSource = ds.Tables("dbo.tmfCNCComponent_threed").DefaultView
con.Close()
Add this attribute to the ComboBox: IsSynchronizedWithCurrentItem="False". By default, CollectionViewSource tracks the selected item in a selector (e.g. ComboBox, ListBox, etc.). If you use the same CollectionViewSource for multiple controls, it will impose the same selection on all of them unless you explicitly prevent that. If you're using the same collection with multiple selectors, there are cases where you want them all to synchronize the selected item. This is not one of those cases.
You need a read-only CellTemplate and an editable CellEditingTemplate. We can use the same template for both, with a ComboBox that's disabled when the cell isn't being edited.
Result:
<DataGrid x:Name="DataGrid" AutoGenerateColumns="False" CellEditEnding="DataGrid_CellEditEnding">
<DataGrid.Resources>
<DataTemplate x:Key="StatusColumnTemplate">
<ComboBox
ItemsSource="{Binding Source={StaticResource StatusItems}}"
SelectedValue="{Binding Status, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Description"
SelectedValuePath="Status"
IsSynchronizedWithCurrentItem="False"
IsEnabled="{Binding IsEditing, RelativeSource={RelativeSource AncestorType=DataGridCell}}"
/>
</DataTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn
Header="Status Shared"
CellTemplate="{StaticResource StatusColumnTemplate}"
CellEditingTemplate="{StaticResource StatusColumnTemplate}"
/>
What you've got now clearly can't work because the grid rows don't have a Description column.
NotifyOnSourceUpdated=True has nothing to do with anything that's happening here.

Single-click-editable bound CheckBox in Xceed DataGridControl

I've spent the past hour searching for solutions to what should be a simple problem: how to create a single-click-editable bound CheckBox in Xceed's community DataGridControl.
To be clear: I want a CheckBox column where the user may click any CheckBox, regardless of what row is selected, and have the view model's IsSelected property changing accordingly.
Below is the latest permutation I've tried. This code reads the value from the model, but clicking the CheckBox does not call the IsSelected setter for some reason.
<xcdg:DataGridControl x:Name="DictionariesDataGridControl" ItemsSource="{Binding Mode=OneWay, Source={StaticResource DictionariesViewSource}}" AutoCreateColumns="False" AutoRemoveColumnsAndDetailConfigurations="False" SelectionMode="Extended" NavigationBehavior="RowOnly">
<xcdg:DataGridControl.View>
<xcdg:TableView UseDefaultHeadersFooters="False" ShowRowSelectorPane="False" VerticalGridLineThickness="0">
<xcdg:TableView.FixedHeaders>
<DataTemplate>
<xcdg:ColumnManagerRow BorderThickness="0"/>
</DataTemplate>
</xcdg:TableView.FixedHeaders>
</xcdg:TableView>
</xcdg:DataGridControl.View>
<xcdg:DataGridControl.Columns>
<xcdg:Column FieldName="IsSelected" MinWidth="20" MaxWidth="20" CellEditorDisplayConditions="RowIsCurrent">
<xcdg:Column.CellContentTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding ., Mode=OneWay}" IsHitTestVisible="False"/>
</DataTemplate>
</xcdg:Column.CellContentTemplate>
<xcdg:Column.CellEditor>
<xcdg:CellEditor>
<xcdg:CellEditor.EditTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding ., Mode=TwoWay}"/>
</DataTemplate>
</xcdg:CellEditor.EditTemplate>
</xcdg:CellEditor>
</xcdg:Column.CellEditor>
</xcdg:Column>
</xcdg:DataGridControl.Columns>
EDIT 1
I'm trying this, which does exactly what I need:
<xcdg:Column FieldName="IsSelected" MinWidth="20" MaxWidth="20" CellEditorDisplayConditions="Always"/>
except that, for some reason, the CheckBox is styled with a blue background!
I've selected the element in the visual tree that has a Background property defined as SolidColorBrush with #FF0000FF as the color:
EDIT 2
I decompiled the DataGridCheckBox class that Xceed uses to render the CheckBox and found this override:
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.ChildCheckBox.Background = (Brush) new SolidColorBrush(Colors.Blue);
}
What a bizarre decision by Xceed to arbitrarily set the background color to blue.
EDIT 3
Using #JBrooks' answer, I tried the following:
<xcdg:Column FieldName="IsSelected" MinWidth="20" MaxWidth="20" CellEditorDisplayConditions="Always">
<xcdg:Column.CellEditor>
<xcdg:CellEditor>
<xcdg:CellEditor.EditTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding ., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</xcdg:CellEditor.EditTemplate>
</xcdg:CellEditor>
</xcdg:Column.CellEditor>
</xcdg:Column>
Unfortunately, for some reason the setter on the IsSelected property is never called when I check the box. The getter is called several times, though, and the CheckBoxes are appearing correctly on initial bind.
You have both a CellContentTemplate and a CellEditor, so the first click does the "go into edit mode" logic. Just have a single one like below. This is for a normal WPF DataGrid, but maybe you can try something similar for your grid.
<DataGridTemplateColumn Header="Active" SortMemberPath="IsActive" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsActive, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}" Style="{StaticResource rightsCB}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
For this DataGrid I also have these properties set:
SelectedItem="{Binding SelectedUser, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectionUnit="FullRow" SelectionMode="Single"
So this DataGrid does act like what you want - I click the checkbox in row 4 and the IsChecked changes and it also makes row 4 the current row which sets the SelectedUser to the user bound to row 4.

WPF DataGrid ItemsSource - Change from ComboBox

Here is a snippet of XAML:
<ComboBox ItemsSource="{Binding UnileverDataSet.Tables, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Margin="5" x:Name="TableNameComboBox">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding TableName}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<DataGrid Margin="5" AutoGenerateColumns="True" ItemsSource="{Binding UnileverDataSet.Tables[TableNameComboBox.SelectedIndex]}"
UnileverDataSet is a DataSet made up of about 12 DataTables
The idea here is that when the ComboBox value changes, the DataGrid should update based on the index value from the ComboBox.
Is this possible or should I look at another way of doing this?
If I do: UnileverDataSet.Tables[0], then all works and data displays correctly.
You can do element binding with combobox..
Your combox will display list of items in the "UnileverDataSet.Tables" collection. When ever your select a item in Combo box the selected item will bounded to the Datagrid Items source (since we are using element binding)
Here is the sample code
<DataGrid Margin="5" AutoGenerateColumns="True" ItemsSource="{Binding SelectedItem,ElementName=TableNameComboBox}">

Update items in ComboBox after lookup value is added

I have a WPF form that contains a DataGrid. This DataGrid is editable. One column of the DataGrid contains a ComboBox with a list of lookup codes for the user to select from.
While editing, the user can add a new lookup code by calling a modal window. When control is returned to the DataGrid, the combobox does not have the new lookupcode.
How can I refresh the list in the combobox after an item is added?
Here is how my combobox is defined. Below is the column of the DataGrid and then my dictionary snippet.
<DataGridTemplateColumn Header="Type" Width="160">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding AddrType.Description}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox Name="cboAddrtype"
ItemsSource="{Binding Source={StaticResource addrTypeList}}"
SelectedValuePath="ID"
DisplayMemberPath="Description"
SelectedValue="{Binding AddrTypeID, UpdateSourceTrigger=PropertyChanged}"
Width="100" />
<Button ToolTip="New" Name="btnNewAddressType" Click="btnNewAddressType_Click">
<Image Source="Images\Add.png" Style="{StaticResource buttonImageStyle}" />
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
The method GetAddressTypes() returns an ObservableCollection.
<ObjectDataProvider x:Key="addrTypeList" IsAsynchronous="True"
MethodName="GetAddressTypes"
ObjectType="{x:Type components:AddressComponent}"/>
I would add the new address to the addrtypeList when the modal window is closed, or the object saved depending on your desired behavior. Because its an observableCollection it should update the combo box automatically.

Resources