Devexpress GridView conditional cell formatting - c#

There is a gridView with Items to buy.
Group
- Checkbox|Item Description
And there is a maximum of items that can be bought on each group.
I want to change the appearance of all not selected rows, when the max is reached (per group).
example:
Select 1 item from each group
Group 1
[ ] Item 1
[ ] Item 2
Group 2
[ ] Item 3
[ ] Item 4
[ ] Item 5
After selection
Group 1
[x] Item 1
[ ] Item 2
Group 2
[ ] Item 3
[x] Item 4
[ ] Item 5
After the max amount of items on each group is checked, I want to alter the appearance of the rest of the items.
I have a group summary for the first column. My problem is that I don't know how to trigger the appearance change of all cells. Is it correct to count selected items on each cell-leave event or is there a better way to accomplish this?

I created Devexpress template with GridControl.
Person class was created for me.
I changed it a little for this example.
public class Person {
public Person(string firstName, string secondName) {
this.FirstName = firstName;
this.SecondName = secondName;
this.Comments = String.Empty;
}
public Person(string firstName, string secondName, string comments)
: this(firstName, secondName) {
this.Comments = comments;
}
public bool Selected
{
get;
set;
}
public bool Blocked
{
get;
set;
}
public string FirstName
{
get;
set;
}
public string SecondName
{
get;
set;
}
public string Comments
{
get;
set;
}
}
My grid looks like this:
And I achived Your functionality with code:
public partial class Form1 : XtraForm
{
int max = 2;
public Form1()
{
InitializeComponent();
InitGrid();
}
List<Person> gridDataList = new List<Person>();
void InitGrid()
{
gridDataList.Add(new Person("John", "Smith"));
gridDataList.Add(new Person("Gabriel", "Smith"));
gridDataList.Add(new Person("Ashley", "Smith", "some comment"));
gridDataList.Add(new Person("Adrian", "Smith", "some comment"));
gridDataList.Add(new Person("Gabriella", "Smith", "some comment"));
gridDataList.Add(new Person("John", "Forester"));
gridDataList.Add(new Person("Gabriel", "Forester"));
gridDataList.Add(new Person("Ashley", "Forester", "some comment"));
gridDataList.Add(new Person("Adrian", "Forester", "some comment"));
gridDataList.Add(new Person("Gabriella", "Forester", "some comment"));
bindingSource1.DataSource = gridDataList;
}
private void gridView1_CellValueChanged(object sender, DevExpress.XtraGrid.Views.Base.CellValueChangedEventArgs e)
{
int parentHandle = gridView1.GetParentRowHandle(e.RowHandle);
int count = gridView1.GetChildRowCount(parentHandle);
int childHandle = -1;
int nCount = 0;
for (int i = 0; i < count; i++)
{
childHandle = gridView1.GetChildRowHandle(parentHandle, i);
Person p = gridView1.GetRow(childHandle) as Person;
if (p != null)
{
p.Blocked = false;
if (p.Selected)
{
nCount++;
}
}
}
if (nCount == max)
{
for (int i = 0; i < count; i++)
{
childHandle = gridView1.GetChildRowHandle(parentHandle, i);
Person p = gridView1.GetRow(childHandle) as Person;
if (p != null && !p.Selected)
{
p.Blocked = true;
}
}
}
// to redraw grid
gridView1.RefreshData();
}
private void richedSelected_EditValueChanged(object sender, EventArgs e)
{
gridView1.PostEditor();
}
private void gridView1_CustomDrawCell(object sender, DevExpress.XtraGrid.Views.Base.RowCellCustomDrawEventArgs e)
{
Person p = gridView1.GetRow(e.RowHandle) as Person;
if (p != null && p.Blocked)
{
e.Appearance.ForeColor = Color.White;
}
}
private void richedSelected_EditValueChanging(object sender, DevExpress.XtraEditors.Controls.ChangingEventArgs e)
{
Person p = gridView1.GetRow(gridView1.FocusedRowHandle) as Person;
if (p != null && p.Blocked)
{
e.Cancel = true;
}
}
}
This is of course simplified implementation. Just to get You on the right track.
Elements from designer:
private DevExpress.XtraGrid.GridControl gridControl;
private DevExpress.XtraGrid.Views.Grid.GridView gridView1;
private System.Windows.Forms.BindingSource bindingSource1;
private DevExpress.XtraGrid.Columns.GridColumn colFirstName;
private DevExpress.XtraGrid.Columns.GridColumn colSecondName;
private DevExpress.XtraGrid.Columns.GridColumn colComments;
private DevExpress.XtraGrid.Columns.GridColumn colSelected;
private DevExpress.XtraEditors.Repository.RepositoryItemCheckEdit richedSelected;
If You find any better solution please let me know.

Here is an example for what I needed link

Related

Remove duplicates from listview depending on first column value

What I'm trying to do is remove duplicate rows in a listView but only if the 1st column is duplicated for example:
NAME / AGE / JOB
John / 24 / Engineer
Tom / 32 / Golfer
John / 55 / Scientist
The name John is in there twice, i would just prefer to have it once, and delete all other rows, this is the basic code i have so far is:
public void RemoveDuplicates() {
for (int i = 0; i < listViewTwitter.Items.Count - 1; i++)
{
if (listViewTwitter.Items[i].Tag == listViewTwitter.Items[i + 1].Tag)
{
listViewTwitter.Items[i + 1].Remove();
}
}
}
I cannot think of the best way to do it, any help would be appreciated.
The below code is an example which I wrote for you.
To make my exmaple better, First I created a class:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Job { get; set; }
}
Then I declared a list of objects of Person class.
private void frmMain_Load(object sender, EventArgs e)
{
var list = new List<Person>()
{
new Person() { Age = 24 , Job = "Engineer", Name = "John" },
new Person() { Age = 32, Job = "Golfer", Name = "Tom " },
new Person() { Age = 55, Job = "Scientist",Name = "John" },
};
foreach (var person in list)
{
ListViewItem item = new ListViewItem(person.Name);
item.Tag = person;
listView1.Items.Add(item);
}
}
Then I remove all dupplicates by pressing a button, with two for-loop
private void btnRemoveDupplicates_Click(object sender, EventArgs e)
{
for (int i=0;i<listView1.Items.Count;i++)
{
var person = (Person)listView1.Items[i].Tag;
for (int j = 0; j < listView1.Items.Count; j++)
{
if(
((Person)listView1.Items[j].Tag).Name == person.Name &&
listView1.Items[i].Index != listView1.Items[j].Index)
{
listView1.Items[j].Remove();
continue;
}
}
}
}

listBox filled with objects

So I have a class called Person. Each Person can have a Name, Age and Email. And I have about 50 Person objects stored in a list called PersonList. Which I defined like this:
List<Person> PersonList = new List<Person>();
The array looks something like this:
PersonList = {
{
name: 'John',
age: 30,
email: 'John#email.com'
},
{
name: 'Bill',
age: 55,
email: 'Bill#email.com'
}
}
I then loop through this and add each of their Name in to a ListBox:
foreach (var Person in PersonList)
{
ListBox.Items.Add(Person.Name);
}
Please note: All names are unique.
What I want to do now, is that when I select a name in the ListBox, I want their Name, Age and Email to be displayed in a label called Label1. Currently, I accomplish this by looping through the PersonList and checking for a name that matches the selected ListBox item's text.
private void ListBox_SelectedIndexChanged(object sender, EventArgs e)
{
foreach (var Person in PersonList)
{
if (Person.Name == ListBox.SelectedItem.ToString())
{
Label1.Text = "Name: " + Person.Name + Environment.NewLine +
"Age: " + Person.Age + Environment.NewLine +
"Email: " + Person.Email;
}
}
}
It works, but is this the correct way of doing it? I feel like constantly looping through the PersonList to compare names could be bad for the performance. What if PersonList contained thousands of objects?
I also wonder if there is a better way to insert all the Person.Name in to the ListBox? Or is looping the way to go? I know about AddRange, but can I do that on just the Person.Name somehow? Note: I only want to add their names in to the ListBox.
What would you do?
You can fill the listbox directly with the list, and the selection of the item can be done in 3 ways, see the code:
public class Pessoa
{
public string Nome { get; set; }
public string Email { get; set; }
public override string ToString()
{
return this.Nome.ToString();
}
}
List<Pessoa> lista = new List<Pessoa>();
private void Form1_Load(object sender, EventArgs e)
{
lista.Add(new Pessoa() { Nome = "Rovann1", Email = "Teste1#Teste.com" });
lista.Add(new Pessoa() { Nome = "Rovann2", Email = "Teste2#Teste.com" });
lista.Add(new Pessoa() { Nome = "Rovann3", Email = "Teste3#Teste.com" });
listBox1.DisplayMember = "Nome";
listBox1.DataSource = lista;
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
label1.Text = "Select one item";
//1
if (listBox1.SelectedItem != null)
{
label1.Text = ((Pessoa)listBox1.SelectedItem).Email;
}
//2
Pessoa p = lista.Find(x => x.Nome == listBox1.SelectedItem.ToString());
if (p != null)
label1.Text = p.Email;
//3
if (listBox1.SelectedIndex >= 0)
label1.Text = lista[listBox1.SelectedIndex].Email;
}

wpf get value by name?

on WPF on c# i have combobox
<ComboBox x:Name="listCombobox" />
and i add it item like
var list = new[]
{
new { Number = 1, Name = "Smith" },
new { Number = 12, Name = "John" } ,
new { Number = 14, Name = "Bon" }
}.ToList();
foreach (var item in list)
{
listCombobox.Items.Add(item.Name);
}
what i want that on the combobox i will see the Name(like now)
but when i selected , on the code behind i will see not the name i selected
i want to see the Number that selected
thanks!
Define a class like this
public class dataObject
{
public int Number { get; set; }
public string Name { get; set; }
}
And fill the data,
List<dataObject> bindingList = new List<dataObject>();
bindingList.Add(new dataObject()
{
Name = "Smith",
Number = 1
});
bindingList.Add(new dataObject()
{
Name = "John",
Number = 12
});
bindingList.Add(new dataObject()
{
Name = "Bon",
Number = 14
});
listCombobox.ItemsSource = bindingList;
listCombobox.DisplayMemberPath = "Name";
On selectionChanged event of the combobox, do this,
private void listCombobox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
dataObject result = (dataObject)listCombobox.SelectedItem;
var selectedNumber = result.Number;
}
I would use a custom ListItem class and assign objects of this type to the ItemSource property of the combobox control like this:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var list = new List<ListItem>
{
new ListItem{ Value = 1, Text = "Smith" },
new ListItem{ Value = 12, Text = "John" } ,
new ListItem{ Value = 14, Text = "Bon" }
}.ToList();
listCombobox.ItemsSource = list;
listCombobox.DisplayMemberPath = "Text";
listCombobox.SelectedValuePath = "Value";
}
private void listCombobox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedItem = (sender as ComboBox).SelectedItem as ListItem;
if (selectedItem != null)
{
// do something with the selected item
}
}
}
public class ListItem
{
public string Text { get; set; }
public int Value { get; set; }
}
I would solve it as follows:
...
foreach (var item in list)
listCombobox.Items.Add(new ComboBoxItem() {
Content = item.Name,
Tag = item.Number
});
You can of course retrieve your Data by using
int mytag = listCombobox.Items[3].Tag;
or
int seletected = listCombobox.SelectedItem.Tag;
MSDN Reference for PresentationFramework.dll::System.Windows.Frameworkelement.Tag
Easiest way, I think, is to put these numbers as Tag of every listCombobox item:
foreach (var item in list) {
listCombobox.Items.Add(new ComboBoxItem { Content = item.Name, Tag = item.Number });
}
And access your number (OnSelectedItemchanged, for example):
void Cb_SelectionChanged(object sender, SelectionChangedEventArgs e) {
int number = (int)((ComboBoxItem) listCombobox.SelectedItem).Tag;
}

searching using a ListView with options

I have a ListView which gets data directly from the database. I want to use it to search for a record using any of the variables, i.e. name, number, or location. Currently I am able to search but using only one variable.
This is my code:
public void searchlist()
{
if (searchbox.Text != "")
{
for (int i = listView1.Items.Count - 1; i >= 0; i--)
{
var item = listView1.Items[i];
if (item.Text.Contains(searchbox.Text))
{
item.BackColor = SystemColors.Highlight;
item.ForeColor = SystemColors.HighlightText;
}
else
{
listView1.Items.Remove(item);
}
}
if (listView1.SelectedItems.Count == 1)
{
listView1.Focus();
}
}
else
{
loadthelist();
}
}
Looks like you need this:
private class TestClass
{
public int Id
{
get;
set;
}
public string Text
{
get;
set;
}
public string Detail
{
get;
set;
}
}
private void ListViewSearch_Load(object sender, EventArgs e)
{
List<TestClass> source = new List<TestClass>();
source.Add(new TestClass { Id = 1, Text = "one", Detail = "D1" });
source.Add(new TestClass { Id = 2, Text = "two", Detail = "D2" });
source.Add(new TestClass { Id = 3, Text = "three", Detail = "D1" });
source.Add(new TestClass { Id = 4, Text = "four", Detail = "D3" });
source.Add(new TestClass { Id = 5, Text = "five", Detail = "D6" });
source.Add(new TestClass { Id = 6, Text = "5", Detail = "D6" });
listView1.Columns.Add("Id");
listView1.Columns.Add("Text");
listView1.Columns.Add("Detail");
source.ForEach(x =>
{
ListViewItem item = new ListViewItem(x.Id.ToString());
item.UseItemStyleForSubItems = false;
item.SubItems.Add(x.Text);
item.SubItems.Add(x.Detail);
listView1.Items.Add(item);
});
listView1.View = View.Details;
listView1.GridLines = true;
comboBox1.DataSource = listView1.Columns;
comboBox1.DisplayMember = "Text";
comboBox1.ValueMember = "Text";
}
private void textBox1_Leave(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(textBox1.Text))
{
foreach (ListViewItem item in listView1.Items)
{
for (int subItemIndex = 0; subItemIndex < item.SubItems.Count; subItemIndex++)
{
if (subItemIndex == comboBox1.SelectedIndex && item.SubItems[subItemIndex].Text.Contains(textBox1.Text))
{
item.SubItems[subItemIndex].BackColor = SystemColors.Highlight;
item.SubItems[subItemIndex].ForeColor = SystemColors.HighlightText;
}
else
{
item.SubItems[subItemIndex].BackColor = Color.Transparent;
item.SubItems[subItemIndex].ForeColor = SystemColors.WindowText;
}
}
}
}
}

How to allow user to change list box order

I am looking for help, I have two lists that both add data to the same list box and it displays them as a summary, I would like to know how to let the user move an index up or down in the list box.
Items are added here
private void BtnAddpickup_Click(object sender, EventArgs e)
{
/*
* This method creates a new pickup object, allows the user to
* enter details and adds it to the List
*
*/
Pickupform.pickup = new Pickups();
//New Visit- note added to the pickupform object
Pickupform.ShowDialog();
//Show the pickupForm. ShowDialog ensures that the form has the exclusive focus until it is closed.
if (Pickupform.pickup != null)
//if null then the "cancel" button was pressed
{
Pickups newpic = Pickupform.pickup;
//Get the Pickup object from the form
thePickup.addPickups(newpic);
//Add the visit to the list
}
updateList();
//Update the list object to reflect the Pickups in the list
}
and this
public Pickups getPickups(int index)
{
//Return the pickup object at the <index> place in the list
int count = 0;
foreach (Pickups pic in pickups)
{
//Go through all the pickup objects
if (index == count)
//If we're at the correct point in the list...
return pic;
//exit this method and return the current visit
count++;
//Keep counting
}
return null;
//Return null if an index was entered that could not be found
}
This is the same for my other class, So any help would be appreciated
You can try something like this. The following code assumes a Windows form containing a ListBox named mainListBox, a button named upButton, and a button named downButton.
public partial class Form1 : Form
{
private class Person
{
public string LastName { get; set; }
public string FirstName { get; set; }
public override string ToString()
{
return string.Format("{0}, {1}", LastName, FirstName);
}
}
public Form1()
{
this.InitializeComponent();
this.mainListBox.SelectionMode = SelectionMode.One;
this.PopulateListBox();
}
private void PopulateListBox()
{
this.mainListBox.Items.Add(new Person() { FirstName = "Joe", LastName = "Smith" });
this.mainListBox.Items.Add(new Person() { FirstName = "Sally", LastName = "Jones" });
this.mainListBox.Items.Add(new Person() { FirstName = "Billy", LastName = "Anderson" });
}
private void upButton_Click(object sender, EventArgs e)
{
if (this.mainListBox.SelectedIndex > 0)
{
int selectedIndex = this.mainListBox.SelectedIndex;
object selectedItem = this.mainListBox.SelectedItem;
this.mainListBox.Items.RemoveAt(selectedIndex);
this.mainListBox.Items.Insert(selectedIndex - 1, selectedItem);
this.mainListBox.SelectedIndex = selectedIndex - 1;
}
}
private void downButton_Click(object sender, EventArgs e)
{
if (this.mainListBox.SelectedIndex > -1 &&
this.mainListBox.SelectedIndex < this.mainListBox.Items.Count - 1)
{
int selectedIndex = this.mainListBox.SelectedIndex;
object selectedItem = this.mainListBox.SelectedItem;
this.mainListBox.Items.RemoveAt(selectedIndex);
this.mainListBox.Items.Insert(selectedIndex + 1, selectedItem);
this.mainListBox.SelectedIndex = selectedIndex + 1;
}
}
}
This will only work if you are adding items to the ListBox using the ObjectCollection.Add method. If you are data binding, you can update the actual data source and use the ListBox's BindingContext to refresh.
private List<Person> people = new List<Person>();
private void PopulateListBox()
{
this.people.Add(new Person() { FirstName = "Joe", LastName = "Smith" });
this.people.Add(new Person() { FirstName = "Sally", LastName = "Jones" });
this.people.Add(new Person() { FirstName = "Billy", LastName = "Anderson" });
this.mainListBox.DataSource = people;
}
private void upButton_Click(object sender, EventArgs e)
{
if (this.mainListBox.SelectedIndex > 0)
{
int selectedIndex = this.mainListBox.SelectedIndex;
Person selectedItem = this.mainListBox.SelectedItem as Person;
this.people.RemoveAt(selectedIndex);
this.people.Insert(selectedIndex - 1, selectedItem);
this.mainListBox.SelectedIndex = selectedIndex - 1;
this.RefreshListSource();
}
}
private void RefreshListSource()
{
CurrencyManager boundList = this.mainListBox.BindingContext[this.people] as CurrencyManager;
boundList.Refresh();
}

Categories

Resources