I see no CellUpdated event in the XamWebGrids event model. I need to be able to trap a checkbox value in a boolean column when taht value is changing. The data source is a dynamic Idictioanry so I can't trap a property changed event, because there is none.
After struggling with this for quite some time, I was finally able to put together 2 different solutions which I hope will save someone time and trouble in the future.
The first solution is to declare the column as follows:
<ig:TemplateColumn Key="IsSelected" HeaderText=" " HorizontalContentAlignment="Center" HeaderTextHorizontalAlignment="Center" IsFilterable="False" Width="25"> <ig:TemplateColumn.ItemTemplate> <DataTemplate> <CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" /> </DataTemplate> </ig:TemplateColumn.ItemTemplate></ig:TemplateColumn>This will cause the checkbox events to be fired both when the end user checks the box AND when the row with the checkbox is scrolled out of sight.This behavior can obviously cause some bizarre behavior in your code, but it is easy to circumvent. The trick is to test if the checkbox IsPressed property is true and only perform your actions if this is the case. For example: Private Sub CheckBox_Unchecked(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Try ' Only process this action if the end user has checked the box If DirectCast(sender, CheckBox).IsPressed Then ' Only process the action if this an actual data row If DirectCast(DirectCast(sender, CheckBox).Parent, CellControl).Cell.Row.RowType = RowType.DataRow Then ' Your actions here End If End If Catch End Try End SubNote that this code also tests the row type to ensure that the action isn't performed when the user clicks on the checkbox in the header.If this doesn't work for some reason (such as the XML loading problem described earlier in the post, the solution is substantially more complex.I tried numerous variations, such as the CellClicked event (which doesn't fire) and the CellControlAttached event (which fires when the row is scrolled out of or into view).It turns out that the solution was to use the ActiveCellChanging event for all but one case: if the user pages up or down. In this case, the ActiveCellChanging event is fired before the checkbox control is attached, so you can't modify the events on the checkbox because it doesn't exist yet. This leads to code that looks like the following: Private WithEvents m_LastCheckBox As CheckBox Private m_LastCheckBoxSpecial As CheckBox Private m_fHandleNextControlAttachment As Boolean Private Sub ugSearch_ActiveCellChanging(ByVal sender As Object, ByVal e As Infragistics.Controls.Grids.ActiveCellChangingEventArgs) Handles ugSearch.ActiveCellChanging Try ' Always clear the last known checkbox m_LastCheckBox = Nothing ' If we have a special last checkbox, release its events, then clear the variable If m_LastCheckBoxSpecial IsNot Nothing Then RemoveHandler m_LastCheckBoxSpecial.Checked, AddressOf CheckBox_Checked RemoveHandler m_LastCheckBoxSpecial.Unchecked, AddressOf CheckBox_Unchecked m_LastCheckBoxSpecial = Nothing End If ' If we have a new active cell, and it is in our target column and not in the header If e.NewActiveCell IsNot Nothing AndAlso e.NewActiveCell.Column.Key = "IsSelected" AndAlso e.NewActiveCell.Row.RowType = RowType.DataRow Then ' If this event is fired because the user paged up or down, then the control will not be attached yet If e.NewActiveCell.Control IsNot Nothing Then ' We have a control, so record the checkbox in the last checkbox member. ' Because the control already exists, assigning it to the member property will automatically pickup the predeclared events m_LastCheckBox = TryCast(e.NewActiveCell.Control.Content, CheckBox) Else ' No control, so indicate we need to process this action in the CellControlAttached method m_fHandleNextControlAttachment = True End If End If Catch End Try End Sub Private Sub ugSearch_CellControlAttached(ByVal sender As Object, ByVal e As Infragistics.Controls.Grids.CellControlAttachedEventArgs) Handles ugSearch.CellControlAttached Try ' If we need to handle the next control attachment, wait for the active cell in our target column If m_fHandleNextControlAttachment AndAlso e.Cell.Column.Key = "IsSelected" AndAlso e.Cell.IsActive Then ' Clear the flag so this action is not processed again until needed m_fHandleNextControlAttachment = False ' Because of the timing, if we assign the checkbox to the m_LastCheckBox property ' the predeclared events will not be fired, so we need to store the checkbox in a different member variable ' so that we can clear the events when this cell is no longer active m_LastCheckBoxSpecial = DirectCast(e.Cell.Control.Content, CheckBox) ' Remove any previous events RemoveHandler m_LastCheckBoxSpecial.Checked, AddressOf CheckBox_Checked RemoveHandler m_LastCheckBoxSpecial.Unchecked, AddressOf CheckBox_Unchecked ' Add the new events AddHandler m_LastCheckBoxSpecial.Checked, AddressOf CheckBox_Checked AddHandler m_LastCheckBoxSpecial.Unchecked, AddressOf CheckBox_Unchecked End If Catch End Try End Sub Private Sub CheckBox_Checked(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles m_LastCheckBox.Checked Try ' Only process this action if the end user has checked the box If DirectCast(sender, CheckBox).IsPressed Then ' Only process the action if this an actual data row If DirectCast(DirectCast(sender, CheckBox).Parent, CellControl).Cell.Row.RowType = RowType.DataRow Then ' Your actions here End If End If Catch End Try End Sub Private Sub CheckBox_Unchecked(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) 'Handles m_LastCheckBox.Unchecked Try ' Only process this action if the end user has checked the box If DirectCast(sender, CheckBox).IsPressed Then ' Only process the action if this an actual data row If DirectCast(DirectCast(sender, CheckBox).Parent, CellControl).Cell.Row.RowType = RowType.DataRow Then ' Your actions here End If End If Catch End Try End SubIn this case the column should NOT be defined with the events in the template.This code actually ensures that the checkbox events only exist for as long as the checkbox cell is active, so you don't have to worry about excess events triggering when the don't need to be.At any rate I hope that this information will save somebody some time and effort.
actually that is exactly what I ended up doing, but I was unaware of the "unhooking" the event issue. I will add that to my code.
This was a bit tricky due to the "dynamic" entity piece.
I also had to add a test for a filter row as this would've thrown an exception
private void grdAvailableVals_CellClicked(object sender, CellClickedEventArgs e){
try
{
if (e.Cell.Row is Infragistics.Silverlight.Controls.Primitives.FilterRow)
return ;
}
else{
if (e.Cell.Column.Key == "IsSelected")
CheckBox cBx = (CheckBox)e.Cell.Row.Cells[0].Control.Content;
cBx.Checked -= new RoutedEventHandler(cBx_Checked);
cBx.Unchecked -= new RoutedEventHandler(cBx_Unchecked);
cBx.Checked += new RoutedEventHandler(cBx_Checked);
cBx.Unchecked += new RoutedEventHandler(cBx_Unchecked);
}catch{
//swallow it
thanks
Nick
Hi,
Hmm, so this is a trickier issue, as my first solution would be to use your ViewModel and my second would have been to use our editing events.
However, from what you described, it sounds like you have to be using a TemplateColumn. So first, i would suggest hooking up the Checked/Unchecked events of the Checkbox in that column.
<DataTemplate><CheckBox Checked="CB_Checked", Unchecked="CB_Unchecked" />
</DataTemplate>
This would do the trick, however, if you're creating the templates via a XamlReader, then that of course won't work.
Which means that your only other choice would be to use the CellControlAttached event, and hook/unhook the events there.
something like:
if(e.Cell.Column.Key == "MyCBCol"){
CheckBox cb = e.Cell.Control.Content as CheckBox;
if(cb != null)
cb.Checked -= CB_Checked;
cb.Checked += CB_Checked
Its important that you remove the eventhandler before you attach it, otherwise you'll wind up hooking the event up multiple times, as cells get recycled.
Also, make sure you are using the latest Service Release, as there used to be an issue, where the content of a TemplateColumn, wouldn't be set during the firing of this event.
Hope this helps,
-SteveZ