This is a migrated thread and some comments may be shown as answers.

Editing multiple cells at once

4 Answers 734 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Sean 2212
Top achievements
Rank 1
Sean 2212 asked on 03 Jun 2011, 01:16 AM
I have created an attached behavior that allows you to select multiple rows in a grid, edit a cell and upon the edit completing, the changed value is applied to the cells in the same column of the selected rows. This works just fine.

However, setting the grid with SelectionMode="Extended" allows multiple rows to be selected but doesn't allow you to use the mouse to click on the selected row and drag to select more rows. I asked about this and Milan advised to use DragElementAction="ExtendedSelect" which is exactly what I wanted but setting it interferes with the selected rows.

Once multiple rows are selected, clicking on the outlined cell on the current row puts the cell into edit mode (as expected) but all the other selected rows disappear. If I remove the DragElementAction property the selected rows do not change when going into edit mode.

The attached behavior I did does not change the selected rows. I would like to be able to retain the multi-edit behavior and the extended selection drag action. SelectionUnit needs to be FullRow. Any help would be appreciated. Thanks.

4 Answers, 1 is accepted

Sort by
0
Milan
Telerik team
answered on 07 Jun 2011, 01:21 PM
Hi Sean 2212,

I am afraid that this is the expected behavior at the moment. you could try using F2 to begin editing.


Greetings,
Milan
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
dpl
Top achievements
Rank 1
answered on 22 Feb 2012, 10:51 AM
Hi Sean 2212,

sorry for pushing this old thread, but can you tell me how you have done it? I have no idea how to attach the behavior.

Many thanks.
0
Sean Craig
Top achievements
Rank 1
answered on 25 Feb 2012, 08:06 AM
Hi, dpl.

We created a behaviour that hooked into the BeginningEdit and CellEditEnded events of the RadGridView. When the cell edit fired, we remembered which rows were selected. Then when the edit ended, we populated the cell in the other selected rows with the new value.

I've included some old code I found using version 2011.10419.40 of the Telerik WPF controls. It's not the best but it's what we had to do to get it to work. Please let me know if you have any questions.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows.Interactivity;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.GridView;
 
namespace Als.Angel.UI.Wpf.Framework.Views.Behaviors
{
    public class GridMultiEditBehaviour : Behavior<RadGridView>
    {
        public RadGridView Grid { get { return AssociatedObject; } }
 
        private static readonly IList<GridViewCellInfo> selectedCells = new List<GridViewCellInfo>();
        private static readonly IList<object> selectedItems = new List<object>();
 
        protected override void OnAttached()
        {
            base.OnAttached();
            Grid.CellEditEnded += RadGridViewCellEditEnded;
            Grid.BeginningEdit += GridBeginningEdit;
        }
 
        static void GridBeginningEdit(object sender, GridViewBeginningEditRoutedEventArgs e)
        {
            var grid = (RadGridView)sender;
 
            switch (grid.SelectionUnit)
            {
                case GridViewSelectionUnit.FullRow:
                    selectedItems.Clear();
                    foreach (var item in grid.SelectedItems)
                    {
                        selectedItems.Add(item);
                    }
                    break;
 
                case GridViewSelectionUnit.Cell:
                    selectedCells.Clear();
                    foreach (var cell in grid.SelectedCells)
                    {
                        selectedCells.Add(cell);
                    }
                    break;
            }
        }
 
        private static void RadGridViewCellEditEnded(object sender, GridViewCellEditEndedEventArgs e)
        {
            var grid = (RadGridView)sender;
 
            if (e.EditAction != GridViewEditAction.Commit)
            {
                return;
            }
 
            switch (grid.SelectionUnit)
            {
                case GridViewSelectionUnit.FullRow:
                    FullRowMultiEdit(e);
                    break;
 
                case GridViewSelectionUnit.Cell:
                    CellMultiEdit(e);
                    break;
            }
        }
 
        private static void CellMultiEdit(GridViewCellEditEndedEventArgs e)
        {
            if (selectedCells.Count < 2)
            {
                return;
            }
 
            var newValue = e.NewData;
 
            foreach (var selected in selectedCells)
            {
                if (e.Cell.Equals(selected) || selected.Column.IsReadOnly)
                {
                    continue;
                }
 
                var item = selected.Item;
                var bindingPath = ((GridViewBoundColumnBase)(selected.Column)).DataMemberBinding.Path;
                if (bindingPath.PathParameters.Any())
                {
                    continue;
                }
 
                var pathProperties = GetPathProperties(item.GetType(), bindingPath.Path);
 
                var canAssignValue = true;
                if (selected is IEditable)
                {
                    if (!(selected as IEditable).IsEditable)
                    {
                        canAssignValue = false;
                    }
                }
 
                if (item is ICanMultiEditProperty)
                {
                    var model = item as ICanMultiEditProperty;
                    var descriptors = model.PropertyAccessDescriptors();
                    var key = pathProperties.Info[0].Name;
 
                    Func<bool> func;
                    if (descriptors.TryGetValue(key, out func))
                    {
                        if (!func())
                        {
                            canAssignValue = false;
                            // If this func return false, it means we can't copy the value to it
                        }
                    }
                }
 
                if (canAssignValue)
                {
                    SetCellPathValue(item, pathProperties, newValue);
                }
            }
        }
 
        private static void SetCellPathValue(object o, PathProperties pathProperties, object value)
        {
            var target = o;
            for (var i = 0; i < pathProperties.Info.Count - 1; i++)
            {
                var pval = pathProperties.Info[i].GetValue(target, null);
                if (pval == null)
                {
                    return;
                }
 
                target = pval;
            }
 
            if (target != null)
            {
                if (pathProperties.PropertyIndex != null)
                {
                    var index = pathProperties.PropertyIndex.ToArray();
                    var obj = pathProperties.Info[pathProperties.Info.Count - 1].GetValue(target, null);
                    obj.GetType().GetProperty("Item").SetValue(obj, value, index);
                }
                else
                {
                    pathProperties.Info[pathProperties.Info.Count - 1].SetValue(target, value, null);
                }
            }
        }
 
        private static void FullRowMultiEdit(GridViewCellEditEndedEventArgs e)
        {
            if (selectedItems.Count < 2)
            {
                return;
            }
 
            var newValue = e.NewData;
            var underlyingRow = e.Cell.DataContext;
            var bindingPath = e.Cell.DataColumn.DataMemberBinding.Path;
            if (bindingPath.PathParameters.Any())
            {
                return;
            }
 
            var pathProperties = GetPathProperties(underlyingRow.GetType(), bindingPath.Path);
 
            foreach (var selected in selectedItems)
            {
                if (underlyingRow.Equals(selected))
                {
                    continue;
                }
 
                var canAssignValue = true;
                if (selected is IEditable)
                {
                    if (!(selected as IEditable).IsEditable)
                    {
                        canAssignValue = false;
                    }
                }
 
                if (selected is ICanMultiEditProperty)
                {
                    var model = selected as ICanMultiEditProperty;
                    var descriptors = model.PropertyAccessDescriptors();
                    var key = bindingPath.Path;
 
                    Func<bool> func;
                    if (descriptors.TryGetValue(key, out func))
                    {
                        if (!func())
                        {
                            canAssignValue = false;
                            // If this func return false, it means we can't copy the value to it
                        }
                    }
                }
 
                if (canAssignValue)
                {
                    SetMultiPathValue(selected, pathProperties, newValue);
                }
            }
        }
 
        private static void SetMultiPathValue(object o, PathProperties pathProperties, object value)
        {
            var target = o;
            for (var i = 0; i < pathProperties.Info.Count - 1; i++)
            {
                var pval = pathProperties.Info[i].GetValue(target, null);
                if (pval == null)
                {
                    return;
                }
 
                target = pval;
            }
 
            if (target != null)
            {
                pathProperties.Info[pathProperties.Info.Count - 1].SetValue(target, value, null);
            }
        }
 
        private static PathProperties GetPathProperties(Type type, string propertyPath)
        {
            var result = new PathProperties();
 
            var currentType = type;
            var pathElements = propertyPath.Split('.');
 
            foreach (var t in pathElements)
            {
                var name = t;
                if (t.EndsWith("]"))
                {
                    var bracketBegin = t.IndexOf('[');
                    var bracketEnd = t.IndexOf(']');
 
                    name = t.Substring(0, bracketBegin);
 
                    var index = Convert.ToInt32(t.Substring(bracketBegin + 1, bracketEnd - bracketBegin - 1));
                    result.PropertyIndex.Add(index);
                }
 
                var pi = currentType.GetProperty(name);
                result.Info.Add(pi);
 
                currentType = pi.PropertyType;
            }
 
            return result;
        }
    }
 
    public class PathProperties
    {
        public IList<PropertyInfo> Info { get; set; }
        public IList<object> PropertyIndex { get; set; }
 
        public PathProperties()
        {
            Info = new List<PropertyInfo>();
            PropertyIndex = new List<object>();
        }
    }
 
    public interface ICanMultiEditProperty
    {
        Dictionary<string, Func<bool>> PropertyAccessDescriptors();
    }
}

0
dpl
Top achievements
Rank 1
answered on 27 Feb 2012, 10:20 AM
Hi Sean,

many thanks. I will try it as soon as possible.
Tags
GridView
Asked by
Sean 2212
Top achievements
Rank 1
Answers by
Milan
Telerik team
dpl
Top achievements
Rank 1
Sean Craig
Top achievements
Rank 1
Share this question
or