I am implementing paging for DataGrid using ObservableCollection<>.
First time it correctly displays 10 records. When click on the Next button, it didn't show the second page. When I debug, I found that PropertyChanged event is not firing when I set currentpagenumber.
My code is
ObservableCollection<RiskSettings> riskCollection = new ObservableCollection<RiskSettings>();
private ObservableCollection<ObservableCollection<RiskSettings>> Pages;
private ObservableCollection<RiskSettings> _ItemsSource;
private ObservableCollection<RiskSettings> _CurrentPage;
public RiskAlert()
{
InitializeComponent();
GeneratePages();
}
private void GeneratePages()
{
if (riskCollection.Count > 0)
{
PageCount = (int)Math.Ceiling(riskCollection.Count / (double)ItemsPerPage);
Pages = new ObservableCollection<ObservableCollection<RiskSettings>>();
for (int i = 0; i < PageCount; i++)
{
ObservableCollection<RiskSettings> page = new ObservableCollection<RiskSettings>();
for (int j = 0; j < ItemsPerPage; j++)
{
if (i * ItemsPerPage + j > riskCollection.Count - 1) break;
page.Add(riskCollection[i * ItemsPerPage + j]);
}
Pages.Add(page);
}
this.CurrentPage = Pages[0];
this.CurrentPageNumber = 1;
}
}
public int CurrentPageNumber
{
get { return _CurrentPageNumber; }
set
{
_CurrentPageNumber = value;
//if (PropertyChanged != null)
this.OnPropertyChanged(new PropertyChangedEventArgs("CurrentPageNumber"));
}
}
public ObservableCollection<RiskSettings> Collection
{
get
{
return riskCollection;
}
set
{
riskCollection = value;
GeneratePages();
}
}
public ObservableCollection<RiskSettings> CurrentPage
{
get { return _CurrentPage; }
set
{
_CurrentPage = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("CurrentPage"));
}
}
public int CurrentPageNumber
{
get { return _CurrentPageNumber; }
set
{
_CurrentPageNumber = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("CurrentPageNumber"));
}
}
public int ItemsPerPage
{
get { return (int)GetValue(ItemsPerPageProperty); }
set { SetValue(ItemsPerPageProperty, value); }
}
public static readonly DependencyProperty ItemsPerPageProperty = DependencyProperty.Register("ItemsPerPage", typeof(int), typeof(RiskAlert), new UIPropertyMetadata(20));
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
I collected all data in riskCollection.My DataGrid Name is grdRiskAlerts
I binded as
GeneratePages();
this.ItemsSource = riskCollection;
grdRiskAlerts.ItemsSource = CurrentPage;
txtTotalRecs.Text = "Total : " + riskCollection.Count();
//txtDispRecs.Text = CurrentPage.Count().ToString();
txtNumOfPages.Text = this.CurrentPageNumber.ToString();
totalRecords = riskCollection.Count();
if (pageSize <= totalRecords)
{
if (totalRecords > 0)
txtDispRecs.Text = "Displaying 1 to " + CurrentPage.Count();
else
txtDispRecs.Text = "Displaying 0 to " + CurrentPage.Count();
}
For this paging stuff i followed one example from google
I do not know why propertychanged event is not firing.
Can any one help on this?
Ramki.
The clear problem is you are setting the value directly rather than updating the binding source. Look if you bind some source to a property then change that property manually, youy break the binding and thats why property change in not firing.
Related
I am a beginner in xamarin android,I want to get the data in a particular row in the table layout.
Please help me..
Here is my Adapter code
public class CaseDetailsAdapter : BaseAdapter<CaseDetails>
{
private readonly Activity context;
private readonly List<CaseDetails> _cases;
int _count;
public TableRow _row;
public static TableLayout _tbLayout;
public TextView _value;
public TableLayout _temp;
public CaseDetailsAdapter(Activity context, List<CaseDetails> model)
{
this.context = context;
this._cases = model;
}
public List<CaseDetails> GetList()
{
return _cases;
}
public override long GetItemId(int position)
{
return position;
}
public override int Count
{
get { return _cases.Count; }
}
public override CaseDetails this[int position]
{
get { return _cases[position]; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var view = convertView;
if (string.IsNullOrEmpty(_cases[position].Description) && string.IsNullOrEmpty(_cases[position].Title) && _cases[position].Files != null)
{
_count = (_cases[position].Files).Count;
view = context.LayoutInflater.Inflate(Resource.Layout.DetailsTable, null);
_temp = (TableLayout)view.FindViewById(Resource.Id.tablelayout_file);
_row = new TableRow(context);
_row.SetPadding(10, 0, 10, 0);
_row.LayoutParameters = new TableLayout.LayoutParams(TableLayout.LayoutParams.WrapContent, TableLayout.LayoutParams.FillParent);
for (int i = 1; i <= _count; i++)
{
_row = new TableRow(context);
_row.SetPadding(10, 0, 10, 0);
_row.LayoutParameters = new TableLayout.LayoutParams(TableLayout.LayoutParams.WrapContent, TableLayout.LayoutParams.FillParent);
TextView _title = new TextView(context);
string _tempTitle = (_cases[position].Files.ElementAt(i).Title);
_title.Text = _tempTitle + "\n";
_title.SetBackgroundResource(Resource.Drawable.border);
_title.Id = i ;
_row.AddView(_title);
_value = new TextView(context);
string _tempValue = (_cases[position].Files.ElementAt(i).Value);
if (_tempValue.Length > 35)
{
_value.Text = System.Text.RegularExpressions.Regex.Replace(_tempValue, ".{35}", "$0\n");
}
else
{
int _length = _tempValue.Length;
for (int j = _length; j < 35; j++)
{
_valueImgName = _tempValue + " ";
}
_value.Text = _valueImgName + "\n";
}
_value.SetBackgroundResource(Resource.Drawable.border);
_row.AddView(_value);
_temp.AddView(_row);
_row.Click += _row_Click;
}
}
else
{
view = context.LayoutInflater.Inflate(Resource.Layout.CaseDetailsDesign, null);
//else case code...
}
return view;
} private void _row_Click(object sender, EventArgs e)
{
//not working
}
}
When I clicking row in the table layout,I want to get the contents in that row (_value.text). And the DetailsTable is located in a single row of a list view.How could I get the data.I think here didn't assign a id to the textview or table row may be that's the reason can't get the data.
You could try to use the GetChildAt() method in your click event.
For example:
private void _row_Click(object sender, EventArgs e)
{
TableRow tableRow = (TableRow)sender;
TextView title = (TextView)tableRow.GetChildAt(0);
TextView value = (TextView)tableRow.GetChildAt(1);
}
Below is a toy program to illustrate the problem I'm having in my real application. It's a DataGridView with a BindingSource to a list of objects of a class.
The problem is: When I click a CheckBox, the CheckBox visibly changes immediately but the invitation_property_changed() method isn't called until I click on some other cell. I need to get the equivalent of the Checkbox.Checked event as soon as it occurs so I can update another control in the UI. (If I change an OTHERS cell, it's natural for the user to hit Enter which triggers the PropertyChanged event - so this one works naturally for the user.)
Here's a screenshot, fwiw:
Here's my toy code:
namespace dgv_binding_test {
public partial class Form1 : Form {
BindingSource bindingsource_invitations = new BindingSource();
class an_invitation : INotifyPropertyChanged {
static int lastID = 0;
int _id;
string _name;
bool _rsvp;
int _others;
public int id() {
return _id;
}
public string NAME {
get { return _name; }
set {
_name = value;
NotifyPropertyChanged("NAME");
}
}
public bool RSVP {
get { return _rsvp; }
set {
_rsvp = value;
NotifyPropertyChanged("RSVP");
}
}
public int OTHERS {
get { return _others; }
set {
_others = value;
NotifyPropertyChanged("OTHERS");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public an_invitation(string a_name, bool a_rsvp, int others) {
_id = lastID++;
_name = a_name;
_rsvp = a_rsvp;
_others = others;
}
private void NotifyPropertyChanged(String propertyName = "") {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
List<an_invitation> invitations = new List<an_invitation>();
public Form1() {
InitializeComponent();
an_invitation ai = new an_invitation("harry", true, 3);
ai.PropertyChanged += new PropertyChangedEventHandler(invitation_property_changed);
invitations.Add(ai);
ai = new an_invitation("heidi", false, 0);
ai.PropertyChanged += new PropertyChangedEventHandler(invitation_property_changed);
invitations.Add(ai);
ai = new an_invitation("henry", false, 0);
ai.PropertyChanged += new PropertyChangedEventHandler(invitation_property_changed);
invitations.Add(ai);
ai = new an_invitation("hazel", true, 0);
ai.PropertyChanged += new PropertyChangedEventHandler(invitation_property_changed);
invitations.Add(ai);
BindingList<an_invitation> bindingList = new BindingList<an_invitation>(invitations);
bindingsource_invitations = new BindingSource(bindingList, null);
dataGridView1.DataSource = bindingsource_invitations;
dataGridView1.AutoGenerateColumns = true;
}
private void invitation_property_changed(object sender, PropertyChangedEventArgs e) {
Debug.Write("change for id: " + ((an_invitation)sender).id() + " property: " + e.PropertyName + " change: " + ((an_invitation)sender).NAME + " to: ");
if (e.PropertyName == "NAME") {
Debug.WriteLine(((an_invitation)sender).NAME);
} else if (e.PropertyName == "RSVP") {
Debug.WriteLine(((an_invitation)sender).RSVP.ToString());
} else if (e.PropertyName == "OTHERS") {
Debug.WriteLine(((an_invitation)sender).OTHERS.ToString());
}
}
}
}
Thanks for your consideration.
The easiest solution I've discovered for this type of situation is to handle the DataGridView.CellContentClick and DataGridView.CellContentDoubleClick events. You can keep all the current code you have. All you'd need to add is a single handle for both of these events which ends the cell edit when it is a CheckBox cell. Ending the edit will trigger the value change the same as leaving the cell currently does.
this.dataGridView1.CellContentClick += DataGridView1_CellContentClick;
this.dataGridView1.CellContentDoubleClick += DataGridView1_CellContentClick;
private void DataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (this.dataGridView1[e.ColumnIndex, e.RowIndex] is DataGridViewCheckBoxCell)
{
this.dataGridView1.EndEdit();
}
}
Prematurely ending a cell's edit can be problematic - say, if it were a TextBox cell - due to validation. But as it's simply True or False, the point is moot in this case.
I have one button on my MasterDetailPage changing the value on an INT (named App.value1) depending on what you click looking like this:
void click1 (object s, EventArgs a)
{
if (App.value1 == 0) {
App.value1 = App.value1 + 1;
} else {
App.value1 = 0;
}
}
And I want this click function to immediately change the value on my StartPage (another ContentPage). So I have created a viewmodel looking like this, where I try to work with the current value:
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged (string propertyName)
{
var changed = PropertyChanged;
if (changed != null) {
PropertyChanged (this, new PropertyChangedEventArgs (propertyName));
}
}
public int currentValue {
get {
return App.value1;
}
set {
if (App.value1 == 0) {
App.value1 = 0;
} else {
App.value1 = 1;
}
}
}
And this is the StartPage where I want the value of the INT to update immediately depending on what you clicked on at the MasterDetailView.
public StartPage ()
{
var ourView = new StartPageViewModel ();
ourCurrentValue = ourView.currentValue;
}
protected async override void OnAppearing()
{
LoadData();
}
private async Task<List<Pin>> LoadData() //I work with pins here (not showing that code though as it is irrelavant.
{
if (ourCurrentValue == 0) {
System.Diagnostics.Debug.WriteLine ("Value is 0");
}
else {
System.Diagnostics.Debug.WriteLine ("Value is 1");
}
}
Right now I only see "Value is 0" in my log. Nothing updates when I click on my button on the MasterDetailPage.
UPDATED CODE:
public class StartPageViewModel : INotifyPropertyChanged
{
private ICommand clickCommand;
private int currentValue;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged (string propertyName)
{
var changed = PropertyChanged;
if (changed != null)
{
PropertyChanged (this, new PropertyChangedEventArgs (propertyName));
}
}
public StartPageViewModel()
{
ClickCommand = new Command(() => CurrentValue = CurrentValue + 1);
}
public ICommand ClickCommand
{
get { return clickCommand; }
set
{
clickCommand = value;
OnPropertyChanged("ClickCommand");
}
}
public int CurrentValue
{
get { return currentValue; }
set
{
currentValue = value;
OnPropertyChanged("CurrentValue");
}
}
}
And StartPage:
public StartPage ()
{
App.PropertyChanged += (sender, args) => OnPropertyChanged("currentValue"); // ERROR: `An object reference is requiered to access non-static member 'Xamarin.Forms.BindableObject.PropertyChanged`
}
You can proceed with something like that:
Make following changes to your App class and value1 property inside that class:
public static event PropertyChangedEventHandler PropertyChanged;
private static void OnPropertyChanged (string propertyName)
{
var changed = PropertyChanged;
if (changed != null)
{
PropertyChanged (null, new PropertyChangedEventArgs (propertyName));
}
}
private static int _value1;
public static int value1
{
get { return _value1; }
set
{
_value1 = value;
OnPropertyChanged("value1");
}
}
Then add this line to your StartPageViewModel constructor:
App.PropertyChanged += (sender, args) => OnPropertyChanged("currentValue");
In that code you are just leveraging PropertyChanged for your own purposes (you can even create your own event for that).
I mean StartPageViewModel subscribes to PropertyChanged event in Appclass, so it will be notified when value1 change. And when it actually occurs, then it is invoking his own PropertyChanged to notify View about currentValue change.
However, I would say better solution is to share View Model between MasterDetailPage and StartPage, because using global state makes your solution hard to understand :
public class SharedViewModel : INotifyPropertyChanged
{
private ICommand clickCommand;
private int currentValue;
/* INotifyPropertyChanged implementation */
public SharedViewModel()
{
ClickCommand = new Command(() => CurrentValue = CurrentValue + 1);
}
public ICommand ClickCommand
{
get { return clickCommand; }
set
{
clickCommand = value;
OnPropertyChanged("ClickCommand");
}
}
public int CurrentValue
{
get { return currentValue; }
set
{
currentValue = value;
OnPropertyChanged("CurrentValue");
}
}
}
And you need to use the same instance of SharedViewModel in MasterDetailPage as well as StartPage
I tried to implement a simple next-previous image preview with two buttons but the code below works only for 3 images. How to make it more dynamic for any number of images? I would appreciate any help.
private void left_arrow_btn_Click(object sender, RoutedEventArgs e)
{
if (x == custom_studio_images.Count - 2)
{
x = custom_studio_images.Count;
//System.Windows.MessageBox.Show(x.ToString());
CustomStudio.Children.RemoveAt(LargePic.Children.Count);
CustomStudio.Children.Add(custom_studio_images.ElementAt(x - 1));
}
else
{
CustomStudio.Children.RemoveAt(LargePic.Children.Count);
CustomStudio.Children.Add(custom_studio_images.ElementAt(x - 2));
//System.Windows.MessageBox.Show(x.ToString());
x--;
}
}
private void right_arrow_btn_Click(object sender, RoutedEventArgs e)
{
if (CustomStudio.Children.Count > 0)
{
CustomStudio.Children.RemoveAt(LargePic.Children.Count); //clear first item in StackPanel
}
if (x == custom_studio_images.Count )
{
x = 0;
CustomStudio.Children.Add(custom_studio_images.ElementAt(x));
x++;
}
else
{
CustomStudio.Children.Add(custom_studio_images.ElementAt(x)); //show picture for next available studio in a set
x++;
}
}
You should implement a MVVM solution with a view model that exposes a list of images, a current image, and two commands that navigate to the previous and next image:
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
PreviousImageCommand = new RelayCommand(PreviousImage);
NextImageCommand = new RelayCommand(NextImage);
}
public event PropertyChangedEventHandler PropertyChanged;
public ICommand PreviousImageCommand { get; set; }
public ICommand NextImageCommand { get; set; }
public List<ImageSource> Images { get; set; }
public ImageSource CurrentImage
{
get
{
if (currentImageIndex < Images.Count)
{
return Images[currentImageIndex];
}
return null;
}
}
private int currentImageIndex;
private void PreviousImage(object o)
{
if (Images.Count > 0)
{
// add Image.Count to avoid negative index
currentImageIndex = (currentImageIndex + Images.Count - 1) % Images.Count;
OnPropertyChanged("CurrentImage");
}
}
private void NextImage(object o)
{
if (Images.Count > 0)
{
currentImageIndex = (currentImageIndex + 1) % Images.Count;
OnPropertyChanged("CurrentImage");
}
}
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You would now bind the properties of this view model in XAML like this:
<Image Source="{Binding CurrentImage}"/>
...
<Button Content="Prev" Command="{Binding PreviousImageCommand}"/>
<Button Content="Next" Command="{Binding NextImageCommand}"/>
In general work with the number of images available.
And if you come past the last one, index the beginning with the modulo operator:
CustomStudio.Children.Add(custom_studio_images.ElementAt(x % custom_studio_images.Count));
The problematic part is your if-statement:
if (x == custom_studio_images.Count - 2)
{
x = custom_studio_images.Count; ...
You're setting it back to the count once you hit count - 2. You never come below this point.
This is my code
gridView1.Columns.Add(new DevExpress.XtraGrid.Columns.GridColumn()
{
Caption = "Selected",
ColumnEdit = new RepositoryItemCheckEdit() { },
VisibleIndex = 1,
UnboundType = DevExpress.Data.UnboundColumnType.Boolean
});
But I cant check multiple checkEdit at the same time.
Why was that?
And please show me the way out.
Thanks.
Well, there are two answers to that question, one very simple, and one very complex, let's start with the simple:
If you want to have an column that has the "Selected" caption and act as a checkbox to indicate that a particular record was selected, you have two options:
1) If you can alter the class in your data source to add a property that is bool and could be used with DataBinding, then, all is done in a very simple way, jast add the property and bind the data and it will work:
class SimplePerson
{
public string Name { get; set; }
public bool IsSelected { get; set; }
}
BindingList<SimplePerson> source = new BindingList<SimplePerson>();
void InitGrid()
{
source.Add(new SimplePerson() { Name = "John", IsSelected = false });
source.Add(new SimplePerson() { Name = "Gabriel", IsSelected = true });
gridControl.DataSource = source;
}
2) You cannot alter you classes, so you need to this by signing the correct grid events and drawing the column yourself, and also adding the right handlers for all the actions.... is a very complex case, but for your luck i have this done, because i have had this problem in the past, so i will post you my full class!
public class GridCheckMarksSelection
{
public event EventHandler SelectionChanged;
protected GridView _view;
protected ArrayList _selection;
private GridColumn _column;
private RepositoryItemCheckEdit _edit;
public GridView View
{
get { return _view; }
set
{
if (_view == value)
return;
if (_view != null)
Detach();
_view = value;
Attach();
}
}
public GridColumn CheckMarkColumn { get { return _column; } }
public int SelectedCount { get { return _selection.Count; } }
public GridCheckMarksSelection()
{
_selection = new ArrayList();
}
public GridCheckMarksSelection(GridView view)
: this()
{
this.View = view;
}
protected virtual void Attach()
{
if (View == null)
return;
_selection.Clear();
_view = View;
_edit = View.GridControl.RepositoryItems.Add("CheckEdit")
as RepositoryItemCheckEdit;
_edit.EditValueChanged += edit_EditValueChanged;
_column = View.Columns.Insert(0);
_column.OptionsColumn.AllowSort = DefaultBoolean.False;
_column.VisibleIndex = int.MinValue;
_column.FieldName = "CheckMarkSelection";
_column.Caption = "Mark";
_column.OptionsColumn.ShowCaption = false;
_column.UnboundType = UnboundColumnType.Boolean;
_column.ColumnEdit = _edit;
View.CustomDrawColumnHeader += View_CustomDrawColumnHeader;
View.CustomDrawGroupRow += View_CustomDrawGroupRow;
View.CustomUnboundColumnData += view_CustomUnboundColumnData;
View.MouseUp += view_MouseUp;
}
protected virtual void Detach()
{
if (_view == null)
return;
if (_column != null)
_column.Dispose();
if (_edit != null)
{
_view.GridControl.RepositoryItems.Remove(_edit);
_edit.Dispose();
}
_view.CustomDrawColumnHeader -= View_CustomDrawColumnHeader;
_view.CustomDrawGroupRow -= View_CustomDrawGroupRow;
_view.CustomUnboundColumnData -= view_CustomUnboundColumnData;
_view.MouseDown -= view_MouseUp;
_view = null;
}
protected virtual void OnSelectionChanged(EventArgs e)
{
if (SelectionChanged != null)
SelectionChanged(this, e);
}
protected void DrawCheckBox(Graphics g, Rectangle r, bool Checked)
{
var info = _edit.CreateViewInfo() as CheckEditViewInfo;
var painter = _edit.CreatePainter() as CheckEditPainter;
ControlGraphicsInfoArgs args;
info.EditValue = Checked;
info.Bounds = r;
info.CalcViewInfo(g);
args = new ControlGraphicsInfoArgs(info, new GraphicsCache(g), r);
painter.Draw(args);
args.Cache.Dispose();
}
private void view_MouseUp(object sender, MouseEventArgs e)
{
if (e.Clicks == 1 && e.Button == MouseButtons.Left)
{
GridHitInfo info;
var pt = _view.GridControl.PointToClient(Control.MousePosition);
info = _view.CalcHitInfo(pt);
if (info.InRow && _view.IsDataRow(info.RowHandle))
UpdateSelection();
if (info.InColumn && info.Column == _column)
{
if (SelectedCount == _view.DataRowCount)
ClearSelection();
else
SelectAll();
}
if (info.InRow && _view.IsGroupRow(info.RowHandle)
&& info.HitTest != GridHitTest.RowGroupButton)
{
bool selected = IsGroupRowSelected(info.RowHandle);
SelectGroup(info.RowHandle, !selected);
}
}
}
private void View_CustomDrawColumnHeader
(object sender, ColumnHeaderCustomDrawEventArgs e)
{
if (e.Column != _column)
return;
e.Info.InnerElements.Clear();
e.Painter.DrawObject(e.Info);
DrawCheckBox(e.Graphics, e.Bounds, SelectedCount == _view.DataRowCount);
e.Handled = true;
}
private void View_CustomDrawGroupRow
(object sender, RowObjectCustomDrawEventArgs e)
{
var info = e.Info as GridGroupRowInfo;
info.GroupText = " " + info.GroupText.TrimStart();
e.Info.Paint.FillRectangle
(e.Graphics, e.Appearance.GetBackBrush(e.Cache), e.Bounds);
e.Painter.DrawObject(e.Info);
var r = info.ButtonBounds;
r.Offset(r.Width * 2, 0);
DrawCheckBox(e.Graphics, r, IsGroupRowSelected(e.RowHandle));
e.Handled = true;
}
private void view_CustomUnboundColumnData
(object sender, CustomColumnDataEventArgs e)
{
if (e.Column != CheckMarkColumn)
return;
if (e.IsGetData)
e.Value = IsRowSelected(View.GetRowHandle(e.ListSourceRowIndex));
else
SelectRow(View.GetRowHandle(e.ListSourceRowIndex), (bool)e.Value);
}
private void edit_EditValueChanged(object sender, EventArgs e)
{
_view.PostEditor();
}
private void SelectRow(int rowHandle, bool select, bool invalidate)
{
if (IsRowSelected(rowHandle) == select)
return;
object row = _view.GetRow(rowHandle);
if (select)
_selection.Add(row);
else
_selection.Remove(row);
if (invalidate)
Invalidate();
OnSelectionChanged(EventArgs.Empty);
}
public object GetSelectedRow(int index)
{
return _selection[index];
}
public int GetSelectedIndex(object row)
{
return _selection.IndexOf(row);
}
public void ClearSelection()
{
_selection.Clear();
View.ClearSelection();
Invalidate();
OnSelectionChanged(EventArgs.Empty);
}
private void Invalidate()
{
_view.CloseEditor();
_view.BeginUpdate();
_view.EndUpdate();
}
public void SelectAll()
{
_selection.Clear();
var dataSource = _view.DataSource as ICollection;
if (dataSource != null && dataSource.Count == _view.DataRowCount)
_selection.AddRange(dataSource); // fast
else
for (int i = 0; i < _view.DataRowCount; i++) // slow
_selection.Add(_view.GetRow(i));
Invalidate();
OnSelectionChanged(EventArgs.Empty);
}
public void SelectGroup(int rowHandle, bool select)
{
if (IsGroupRowSelected(rowHandle) && select) return;
for (int i = 0; i < _view.GetChildRowCount(rowHandle); i++)
{
int childRowHandle = _view.GetChildRowHandle(rowHandle, i);
if (_view.IsGroupRow(childRowHandle))
SelectGroup(childRowHandle, select);
else
SelectRow(childRowHandle, select, false);
}
Invalidate();
}
public void SelectRow(int rowHandle, bool select)
{
SelectRow(rowHandle, select, true);
}
public bool IsGroupRowSelected(int rowHandle)
{
for (int i = 0; i < _view.GetChildRowCount(rowHandle); i++)
{
int row = _view.GetChildRowHandle(rowHandle, i);
if (_view.IsGroupRow(row))
if (!IsGroupRowSelected(row))
return false;
else
if (!IsRowSelected(row))
return false;
}
return true;
}
public bool IsRowSelected(int rowHandle)
{
if (_view.IsGroupRow(rowHandle))
return IsGroupRowSelected(rowHandle);
object row = _view.GetRow(rowHandle);
return GetSelectedIndex(row) != -1;
}
public void UpdateSelection()
{
_selection.Clear();
Array.ForEach(View.GetSelectedRows(), item => SelectRow(item, true));
}
}
And now you need to know how to use this:
void InitGrid()
{
gridControl.DataSource = source;
// Do this after the database for the grid is set!
selectionHelper = new GridCheckMarksSelection(gridView1);
// Define where you want the column (0 = first)
selectionHelper.CheckMarkColumn.VisibleIndex = 0;
// You can even subscrive to the event that indicates that
// there was change in the selection.
selectionHelper.SelectionChanged += selectionHelper_SelectionChanged;
}
void selectionHelper_SelectionChanged(object sender, EventArgs e)
{
// Do something when the user selects or unselects something
}
But how do you retrieve all the selected items? There is a example assuming that the type bond is 'Person'
/// <summary>
/// Return all selected persons from the Grid
/// </summary>
public IList<Person> GetItems()
{
var ret = new List<Person>();
Array.ForEach
(
gridView1.GetSelectedRows(),
cell => ret.Add(gridView1.GetRow(cell) as Person)
);
return ret;
}