locked
Datagrid Make the only row editable whose edit button is clicked , and other rows should not be editable RRS feed

  • Question

  • Datagrid

    <DataGrid  x:Name="TimeEntryGrid"
    					EnableRowVirtualization="True"
    					AutoGenerateColumns="False"
    					CanUserAddRows="False"
    					ItemsSource="{Binding Source={StaticResource TimeEntriesCollectionViewSource} }"
    					HeadersVisibility="Column">
    					
    					<DataGrid.IsReadOnly>
    						<MultiBinding Converter="{StaticResource GridReadonlyConverter}">
    							<Binding UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True"  Path="DataContext.IsPausePlayModeEnabled"  RelativeSource="{RelativeSource AncestorType={x:Type UserControl}}" />
    							<Binding UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True"  Path="DataContext.CanEndTaskVar" RelativeSource="{RelativeSource AncestorType={x:Type UserControl}}" />
    						</MultiBinding>
    					</DataGrid.IsReadOnly>

    I have columns with datatemplates and editdaatemplates defined and button columns , one is combobox , other having textblock in datatemplate and textbox in editdatatemplate

    Datagrid columns  Edit button

    <DataGridTemplateColumn MinWidth="90" Header="Edit"  HeaderStyle="{StaticResource gridHeaderStyle}">
    							<DataGridTemplateColumn.CellTemplate>
    								<DataTemplate>
    									<Grid>
    										<Grid.RowDefinitions>
    											<RowDefinition>
    											</RowDefinition>
    										</Grid.RowDefinitions>
    										<Grid.ColumnDefinitions>
    											<ColumnDefinition>
    											</ColumnDefinition>
    										</Grid.ColumnDefinitions>
    										<Button
    											x:Name="btnEdit"
    											Grid.Column="0"
    											Grid.Row="0"
    											VerticalAlignment="Center"
    											Command="{Binding DataContext.EditCommand, NotifyOnSourceUpdated=True, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True }"
    											CommandParameter="{Binding SelectedItem, NotifyOnSourceUpdated=True, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, UpdateSourceTrigger=PropertyChanged}"
    											Visibility="{Binding IsEditVisible,Converter={StaticResource EditVisibiltyConverter }}">
    											<Button.IsEnabled>
    												<MultiBinding Converter="{StaticResource editEnabledConverter}" FallbackValue="False">
    													<Binding NotifyOnSourceUpdated="True" Path="Project.ID" UpdateSourceTrigger="PropertyChanged" ValidatesOnExceptions="True">
    													</Binding>
    													<Binding NotifyOnSourceUpdated="True" Path="DataContext.IsPastEntryEnabled" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" UpdateSourceTrigger="PropertyChanged" ValidatesOnExceptions="True"  FallbackValue="False">
    													</Binding>
    													<Binding NotifyOnSourceUpdated="True" Path="DataContext.LastSalaryDate" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" UpdateSourceTrigger="PropertyChanged" ValidatesOnExceptions="True">
    													</Binding>
    													<Binding NotifyOnSourceUpdated="True" Path="DataContext.CurrentDate" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" UpdateSourceTrigger="PropertyChanged" ValidatesOnExceptions="True">
    													</Binding>
    												</MultiBinding>
    											</Button.IsEnabled>
    											<Button.Content>
    												<MultiBinding Converter="{StaticResource ButtonContentConverter }">
    													<Binding NotifyOnSourceUpdated="True" Path="Project.ID" UpdateSourceTrigger="PropertyChanged">
    													</Binding>
    													<Binding NotifyOnSourceUpdated="True" Path="RequestedEdit" UpdateSourceTrigger="PropertyChanged">
    													</Binding>
    													<Binding NotifyOnSourceUpdated="True" Path="DataContext.RequestedIds" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" UpdateSourceTrigger="PropertyChanged">
    													</Binding>
    													<Binding NotifyOnSourceUpdated="True" Path="ID" UpdateSourceTrigger="PropertyChanged">
    													</Binding>
    												</MultiBinding>
    											</Button.Content>
    										</Button>
    										<Button
    											x:Name="btnUpdate"
    											Grid.Column="0"
    											Grid.Row="0"
    											VerticalAlignment="Center"
    											Command="{Binding DataContext.UpdateGridCommand,NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True ,RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
    											CommandParameter="{Binding SelectedItem, NotifyOnSourceUpdated=True, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, UpdateSourceTrigger=PropertyChanged}"
    											Content="Update"
    											Visibility="{Binding IsUpdateVisible, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, Converter={StaticResource EditVisibiltyConverter }}">
    										</Button>
    									</Grid>
    									<DataTemplate.Triggers>
    										<DataTrigger Binding="{Binding Project.ID }" Value="999">
    											<Setter TargetName="btnEdit" Property="Button.IsEnabled" Value="true">
    											</Setter>
    										</DataTrigger>
    										<DataTrigger Binding="{Binding Project.ID}" Value="9999">
    											<Setter TargetName="btnEdit" Property="Button.IsEnabled" Value="true">
    											</Setter>
    										</DataTrigger>
    									</DataTemplate.Triggers>
    								</DataTemplate>
    							</DataGridTemplateColumn.CellTemplate>
    						</DataGridTemplateColumn>

    Editable columns

    <DataGridTemplateColumn Width="1.1*" Header="Project" HeaderStyle="{StaticResource gridHeaderStyle}">
    							<DataGridTemplateColumn.CellTemplate>
    								<DataTemplate>
    									<TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" Padding="4" Text="{Binding Project.Name}" />
    								</DataTemplate>
    							</DataGridTemplateColumn.CellTemplate>
    							<DataGridTemplateColumn.CellEditingTemplate>
    								<DataTemplate>
    									<ComboBox
    										MaxHeight="40"
    										SelectedValue="{Binding Path=Project.ID,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}"
    										SelectedValuePath="ID"
    										ItemsSource="{Binding DataContext.Projects,RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
    										SelectedItem="{Binding Path=Project, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}"
    										DisplayMemberPath="Name"
    										IsEnabled="{Binding Project.ID, Converter={StaticResource IdleProjectDisabled}, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}">
    										<ComboBox.Resources>
    											<converters:ComboBoxItemEnabledDisabledConverter x:Key="comboBoxItemConverter" />
    										</ComboBox.Resources>
    										<ComboBox.ItemContainerStyle>
    											<Style TargetType="ComboBoxItem">
    												<Setter Property="IsEnabled" Value="{Binding Converter= {StaticResource comboBoxItemConverter}, ConverterParameter=999}" />
    											</Style>
    										</ComboBox.ItemContainerStyle>
    									</ComboBox>
    								</DataTemplate>
    							</DataGridTemplateColumn.CellEditingTemplate>
    						</DataGridTemplateColumn>
    
    						<DataGridTemplateColumn Width="1.1*" Header="Task" HeaderStyle="{StaticResource gridHeaderStyle}">
    							<DataGridTemplateColumn.CellTemplate>
    								<DataTemplate>
    									<TextBlock
    										VerticalAlignment="Center"
    										Padding="3,0,0,0"
    										Text="{Binding Task}"
    										TextWrapping="Wrap"
    										xml:space="preserve" />
    								</DataTemplate>
    							</DataGridTemplateColumn.CellTemplate>
    							<DataGridTemplateColumn.CellEditingTemplate>
    								<DataTemplate>
    									<TextBox
    										VerticalAlignment="Center"
    										Padding="3,0,0,0"
    										Text="{Binding Task, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}"
    										TextWrapping="Wrap"
    
    										xml:space="preserve" />
    								</DataTemplate>
    							</DataGridTemplateColumn.CellEditingTemplate>
    						</DataGridTemplateColumn>
    
    						<DataGridTemplateColumn Width="3*" Header="Description" HeaderStyle="{StaticResource gridHeaderStyle}" ScrollViewer.IsDeferredScrollingEnabled="True">
    							<DataGridTemplateColumn.CellTemplate >
    								<DataTemplate >
                                        <ScrollViewer  VerticalScrollBarVisibility="Auto" Width="Auto"  MouseDoubleClick="ScrollViewer_MouseDoubleClick" CanContentScroll="True" Height="Auto" MaxHeight="100" >
    										<TextBlock
    										    Text="{Binding Description}"
    										    Height="Auto"
    											Width="Auto"
    											TextWrapping="Wrap"
    											xml:space="preserve" />
    									</ScrollViewer>
    								</DataTemplate>
    							</DataGridTemplateColumn.CellTemplate>
    							<DataGridTemplateColumn.CellEditingTemplate>
    								<DataTemplate>
                                        <ScrollViewer  VerticalScrollBarVisibility="Auto" Width="Auto"  CanContentScroll="True" Height="Auto" MaxHeight="100" >
    										<TextBox
    											AcceptsReturn="True"
    											Width="Auto"
    											Height="Auto"
    											Text="{Binding Description, NotifyOnTargetUpdated=True,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
    											TextWrapping="Wrap"
    											xml:space="preserve" />
    										</ScrollViewer>
    								</DataTemplate>
    							</DataGridTemplateColumn.CellEditingTemplate>
    						</DataGridTemplateColumn

    I want to make the columns of the row editable whose edit button is clicked and property of datagrid IsReadonly (bind to viewmodel property done using multivalueconverter) is false  ,  Other rows should not be editable at the same time.  How I can do this in xaml or programmatically.

    Wednesday, May 20, 2015 5:03 AM

Answers

  • Please refer to the following thread for an example of how you could set the IsEditing property of cells to true to put them into edit mode programmatically: https://social.msdn.microsoft.com/Forums/en-US/860bdc68-e9fc-41cb-87c6-49bc264c892d/datagrid-display-edit-control-on-mouse-over?forum=wpf

    You could do this in the click event handler for your "edit" button instead of doing it in the OnMouseEnter event handler like in the sample code from the above thread. The following code snipper should give you the idea:

     private void OnEditClick(object sender, MouseEventArgs e) {
          Button button = sender as Button;
          DataGridRow row = FindVisualParent<DataGridRow>(button);
          DataGridCellsPresenter presenter = FindVisualChild<DataGridCellsPresenter>(row);
          var viewModel = this.DataContext as YourViewModelType;
          for (int i = 0; i < dGrid.Columns.Count; ++i) {
            DataGridCell cell = presenter.ItemContainerGenerator.ContainerFromIndex(i) as DataGridCell;
            if (cell != null)
              cell.IsEditing = viewModel.IsPausePlayModeEnabled && CanEndTaskVar; //or whatever your logic is...
          }
        }
    
    private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
            {
                var parent = VisualTreeHelper.GetParent(dependencyObject);
     
                if (parent == null) return null;
     
                var parentT = parent as T;
                return parentT ?? FindParent<T>(parent);
            }
    

    Hope that helps.

    Note that the forums are not for anyone to write some complete functionality for you though:=) But the above code should definitely get you started and help you implement your desired functionality.

    Please remember to mark helpful posts as answer to close your threads and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    Wednesday, May 20, 2015 10:12 AM
  • Hi Magnus

    Thank you very much for your answer , I tried your approach , but was not able to completely solve the problem.

    But this helped me to think in another way and led me to a simple solution, if  update is visible I made datagrid readonly false else  datagrid readonly true on selecteditemchanged event , this disallowed to get editable row on selection of other rows and if update is visible then I am able to edit the row

    And on edit button click I made datagrid readonly false , and if its playpause mode condition satisfied it allowed to edit when edit is clicked and if update button is visible , worked perfectly

    Thanks a lot


    Ramesh


    Tuesday, May 26, 2015 12:50 PM

All replies

  • If the datagrid is readonly you can't edit anyhow so that's already done.

    I don't really follow the plan with this button it seems pointless.

    You click a row and it switches that row into edit mode.

    You can only edit that row.

    Why would you want the button at all?


    Hope that helps.

    Technet articles: WPF: Change Tracking; All my Technet Articles

    Wednesday, May 20, 2015 7:48 AM
  • Please refer to the following thread for an example of how you could set the IsEditing property of cells to true to put them into edit mode programmatically: https://social.msdn.microsoft.com/Forums/en-US/860bdc68-e9fc-41cb-87c6-49bc264c892d/datagrid-display-edit-control-on-mouse-over?forum=wpf

    You could do this in the click event handler for your "edit" button instead of doing it in the OnMouseEnter event handler like in the sample code from the above thread. The following code snipper should give you the idea:

     private void OnEditClick(object sender, MouseEventArgs e) {
          Button button = sender as Button;
          DataGridRow row = FindVisualParent<DataGridRow>(button);
          DataGridCellsPresenter presenter = FindVisualChild<DataGridCellsPresenter>(row);
          var viewModel = this.DataContext as YourViewModelType;
          for (int i = 0; i < dGrid.Columns.Count; ++i) {
            DataGridCell cell = presenter.ItemContainerGenerator.ContainerFromIndex(i) as DataGridCell;
            if (cell != null)
              cell.IsEditing = viewModel.IsPausePlayModeEnabled && CanEndTaskVar; //or whatever your logic is...
          }
        }
    
    private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
            {
                var parent = VisualTreeHelper.GetParent(dependencyObject);
     
                if (parent == null) return null;
     
                var parentT = parent as T;
                return parentT ?? FindParent<T>(parent);
            }
    

    Hope that helps.

    Note that the forums are not for anyone to write some complete functionality for you though:=) But the above code should definitely get you started and help you implement your desired functionality.

    Please remember to mark helpful posts as answer to close your threads and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    Wednesday, May 20, 2015 10:12 AM
  • Hi Magnus

    Thank you very much for your answer , I tried your approach , but was not able to completely solve the problem.

    But this helped me to think in another way and led me to a simple solution, if  update is visible I made datagrid readonly false else  datagrid readonly true on selecteditemchanged event , this disallowed to get editable row on selection of other rows and if update is visible then I am able to edit the row

    And on edit button click I made datagrid readonly false , and if its playpause mode condition satisfied it allowed to edit when edit is clicked and if update button is visible , worked perfectly

    Thanks a lot


    Ramesh


    Tuesday, May 26, 2015 12:50 PM