I'm using the XamDataGrid v14.2 and want to add the feature of dragging and dropping rows within the datagrid.
I've looked thru the Infragistics forum posts, but most of the code samples show dragging and dropping rows from one grid to another.
Is it possible to drag and drop rows within the same grid? The effect that I want to achieve is to move the sequence of the Web Announcement row numbers.
Here is an image of how the grid looks:
I posted a sample with a behavior a few months ago on the Infragistics Forums that reorders rows that it similar to your requirement.
Relevant markup:
<igDP:XamDataGrid DataSource="{Binding Items}" IsSynchronizedWithCurrentItem="True" GroupByAreaLocation="None">
<i:Interaction.Behaviors>
<DragGrid:XamDataGridDragDropBehavior/>
</i:Interaction.Behaviors>
</igDP:XamDataGrid>
C# code for the Behavior:
using System;
using System.Collections.Generic;
using Infragistics.Windows.DataPresenter;
using System.Windows.Interactivity;
using System.Windows;
using Infragistics.DragDrop;
using System.Windows.Input;
using Infragistics.Windows;
using System.Collections;
using System.Windows.Media;
using System.Reflection;
namespace DragGrid
{
public class XamDataGridDragDropBehavior : Behavior<DataPresenterBase>
{
private DataPresenterBase dataPresenter;
protected override void OnAttached()
{
base.OnAttached();
dataPresenter = this.AssociatedObject;
EventManager.RegisterClassHandler(typeof(XamDataGrid), UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(XamDataGrid_MouseLeftButtonDown));
var dataPresenterStyle = new Style(typeof(DataRecordPresenter));
dataPresenterStyle.Setters.Add(new EventSetter(FrameworkElement.LoadedEvent, new RoutedEventHandler(OnRecordPresenterLoaded)));
dataPresenter.Resources.Add(typeof(DataRecordPresenter), dataPresenterStyle);
DropTarget dropTarget = new DropTarget() { IsDropTarget = true };
DragDropManager.SetDropTarget(dataPresenter, dropTarget);
}
private void OnRecordPresenterLoaded(object sender, RoutedEventArgs e)
{
var recordPresenter = sender as DataRecordPresenter;
if (DragDropManager.GetDragSource(recordPresenter) != null)
{
return;
}
var dragSource = new DragSource
{
IsDraggable = true
};
dragSource.DragStart += new System.EventHandler<DragDropStartEventArgs>(dragSource_DragStart);
dragSource.Drop += OnRecordDragDrop;
dragSource.DragTemplate = ((Window)Utilities.GetAncestorFromType(this.dataPresenter, typeof(Window), true)).Resources["dragTemplate"] as DataTemplate;
DragDropManager.SetDragSource(recordPresenter, dragSource);
}
void dragSource_DragStart(object sender, DragDropStartEventArgs e)
{
ArrayList draggedItems = new ArrayList();
List<IList> sourceList = new List<IList>();
SelectedRecordCollection selectedRecords = this.dataPresenter.SelectedItems.Records;
DataRecord lastSelectedDataRecord = null;
foreach (Record r in selectedRecords)
{
DataRecord dr = r as DataRecord;
if (dr != null)
{
lastSelectedDataRecord = dr;
draggedItems.Add(dr.DataItem);
sourceList.Add(GetSourceList(dr));
}
}
DraggingData data = new DraggingData();
data.Items = draggedItems;
data.Lists = sourceList;
if (lastSelectedDataRecord != null && lastSelectedDataRecord.ParentRecord != null)
{
data.SourceProperty = lastSelectedDataRecord.RecordManager.Field.Name;
}
e.Data = data;
}
private IList GetSourceList(DataRecord record)
{
IList retVal = null;
DataRecord parent = record.ParentDataRecord;
if (parent == null)
{
// There is no parent, use the grids list
retVal = this.dataPresenter.DataSource as IList;
}
else
{
object parentDataItem = parent.DataItem;
Type dataItemType = parentDataItem.GetType();
PropertyInfo listProperty = dataItemType.GetProperty(record.RecordManager.Field.Name);
retVal = listProperty.GetValue(parentDataItem, null) as IList;
}
return retVal;
}
private void OnRecordDragDrop(object sender, DropEventArgs dragInfo)
{
var result = VisualTreeHelper.HitTest(dragInfo.DropTarget, dragInfo.GetPosition(dragInfo.DropTarget));
var targetElement = Utilities.GetAncestorFromType(result.VisualHit, typeof(DataRecordPresenter), true) as DataRecordPresenter;
if (targetElement != null)
{
DataRecord targetRecord = targetElement.DataRecord;
IList targetList = GetSourceList(targetRecord);
object targetItem = targetRecord.DataItem;
Type targetType = targetItem.GetType();
DraggingData draggedData = dragInfo.Data as DraggingData;
if (draggedData != null)
{
IList itemsList = draggedData.Items;
object firstItem = itemsList[0];
IList<IList> listsList = draggedData.Lists;
if (!targetType.IsInstanceOfType(firstItem))
{
// the target type doesn't match the items we are dropping, get the child list from the parent if we have a property.
if (draggedData.SourceProperty != null)
{
PropertyInfo listProperty = targetType.GetProperty(draggedData.SourceProperty);
targetList = listProperty.GetValue(targetItem, null) as IList;
if (targetList != null)
{
for (int i = itemsList.Count - 1; i >= 0; i--)
{
object currentItem = itemsList[i];
int targetIndex = targetList.IndexOf(targetItem);
listsList[i].Remove(currentItem);
targetList.Add(currentItem);
}
}
}
else
{
MessageBox.Show("Can't drop here");
}
}
else
{
for (int i = itemsList.Count - 1; i >= 0; i--)
{
object currentItem = itemsList[i];
int targetIndex = targetList.IndexOf(targetItem);
listsList[i].Remove(currentItem);
targetList.Insert(targetIndex, currentItem);
}
}
}
}
}
void XamDataGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (this.dataPresenter.Equals(sender))
{
DataRecordPresenter drp = Utilities.GetAncestorFromType(e.OriginalSource as DependencyObject, typeof(DataRecordPresenter), true) as DataRecordPresenter;
if (drp != null)
{
// If we already have a selection then we don't want the Grids SelectionController to be called which will cause a capture of the mouse and prevent dragging.
if (drp.IsSelected)
{
e.Handled = true;
}
}
}
}
}
}
Related
How can I check all the records filtered by CheckAllBox event without using visible rows? (now it checks only the ones that visible on the screen).
this is the code behind:
private void CheckAllBox_OnClick(object sender, RoutedEventArgs e){
var grid = itemsGrid;
VisibleRows = new List<string>();
if (grid == null)
return;
//Getting the visible rows in dataGrid after filter
foreach (var item in grid.Items)
{
var row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromItem(item);
if (row == null) continue;
if (row.TransformToVisual(grid).Transform(new Point(0, 0)).Y + row.ActualHeight >= grid.ActualHeight) break;
var item = (ItemParameter)row.DataContext;
VisibleRows.Add(qdf.Qdf);
}
var vm = (ItemsPaneViewModel)DataContext;
var checkBox = (CheckBox)sender;
if (checkBox.IsChecked == null) return;
var value = checkBox.IsChecked.Value;
foreach (var ItemParameter in vm.ItemParameters)
{
if (VisibleRows.Contains(ItemParameter.Name))
ItemParameter.IsEnable = value;
}
}
Thanks!
I set a List have 2 elements to the dataGridView's DataSource, but it's always have one row, the RowCount property is 1. This is so strange
My code below have some Entity class name which I must explain.
HoaDon is Order
ChiTietHoaDon is OrderDetail
SanPham is Product
Code:
using GymFitnessOlympic.Controller;
using GymFitnessOlympic.Models;
using GymFitnessOlympic.Models.Util;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace GymFitnessOlympic.View.ActForm
{
public partial class FrmBanHang2 : Form
{
List<SanPham> allSanPham;
List<ChiTietHoaDon> allChiTiet = new List<ChiTietHoaDon>();
HoaDon hoaDon = new HoaDon();
public FrmBanHang2()
{
InitializeComponent();
int phongID = Login.GetPhongHienTai().MaPhongTap;
allSanPham = SanPhamController.GetList(phongID);
dgrChiTiet.AutoGenerateColumns = false;
dgrChiTiet.AutoGenerateColumns = false;
loadListSanPham(allSanPham);
}
void loadListSanPham(List<SanPham> li)
{
lbSanPham.DataSource = li;
}
void updateTable()
{
dgrChiTiet.DataSource = allChiTiet;
int n = dgrChiTiet.RowCount;
}
private void btnAdd_Click(object sender, EventArgs e)
{
if (spnQuantity.Value <= 0)
{
dxErrorProvider1.SetError(spnQuantity, "Quantity must be greater than 0");
spnQuantity.Focus();
return;
}
int gia;
if (!int.TryParse(txtPrice.Text, out gia) || (gia % 500 != 0) || gia <= 0)
{
txtPrice.Focus();
dxErrorProvider1.SetError(txtPrice, "Invalid Price");
return;
}
if (lbSanPham.SelectedItem != null)
{
var sp = (SanPham)lbSanPham.SelectedItem;
int soLuong = int.Parse(spnQuantity.Text);
ChiTietHoaDon c = new ChiTietHoaDon()
{
Gia = gia,
MaSanPham = sp.MaSanPham,
SoLuong = soLuong,
SanPham = sp
};
var old = allChiTiet.FirstOrDefault(c1 => c1.MaSanPham == c.MaSanPham);
if (old != null)
{
old.SoLuong += c.SoLuong;
}
else
{
allChiTiet.Add(c);
}
}
updateTable();
}
private void lbSanPham_SelectedIndexChanged(object sender, EventArgs e)
{
if (lbSanPham.SelectedItem != null)
{
var sp = (SanPham)lbSanPham.SelectedItem;
txtTenSanPham.Text
= sp.TenSanPham;
txtPrice.Text = sp.Gia.ToString();
spnQuantity.Text = "1";
}
}
}
}
This is because you are using List<ChiTietHoaDon> as data source of your datagridview and it doesn't notify changes so the grid doesn't show new items.
You should use BindingList<ChiTietHoaDon> instead.
But if you want to continue using List<ChiTietHoaDon>, to update the grid you can first set dgrChiTiet.DataSource=null; and then dgrChiTiet.DataSource = allChiTiet;
I am creating an application with an XML file called star.xml to store my data in a list view. I am very new to c# and programming and need any help
Basically, I want to be able to type in my search text box (called 'search') and for my list view (lstStar) to only show the matching records. I.e. typing in 'Audi' will only return those items.
any help will be much appreciated
jen
namespace StarinCar
{
public partial class MainWindow : Window
{
int hot = -2;
int Mildly_Moist = -2;
int Wet = -4;
int Very_Wet = -6;
private ObservableCollection<star> starData;
public MainWindow()
{
InitializeComponent();
starData = new ObservableCollection<star>();
lstStar.ItemsSource = starData;
try
{
XmlSerializer xs = new XmlSerializer(typeof(ObservableCollection<star>));
using (StreamReader rd = new StreamReader("star.xml"))
{
starData = xs.Deserialize(rd) as ObservableCollection<star>;
}
}
catch
{
}
lstStar.ItemsSource = starData;
lblAverage.Content = starData.Average(i => i.time).ToString();
lblFastest.Content = starData.Min(i => i.time).ToString();
lblSlowest.Content = starData.Max(i => i.time).ToString();
}
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
star newStar = new star();
newStar.firstName = txtName.Text;
newStar.time = int.Parse(txtTime.Text);
newStar.car = txtCar.Text;
newStar.track = txtTrack.Text;
starData.Add(newStar);
if (txtTrack.Text.Contains("Hot") || (txtTrack.Text.Contains("hot") == true))
{
newStar.time = int.Parse(txtTime.Text) + hot;
}
if (txtTrack.Text.Contains("Mildly Moist") || (txtTrack.Text.Contains("mildly moist")) == true)
{
newStar.time = int.Parse(txtTime.Text) + Mildly_Moist;
}
if (txtTrack.Text.Contains("Wet") || (txtTrack.Text.Contains("wet") == true))
{
newStar.time = int.Parse(txtTime.Text) + Wet;
}
if (txtTrack.Text.Contains("Very Wet") || (txtTrack.Text.Contains("very wet")) == true)
{
newStar.time = int.Parse(txtTime.Text) + Very_Wet;
}
}
private void Window_Closed(object sender, EventArgs e)
{
XmlSerializer xs = new XmlSerializer(typeof(ObservableCollection<star>));
using (StreamWriter wr = new StreamWriter("star.xml"))
{
xs.Serialize(wr, starData);
}
}
}
}
You could use ICollectionView. So you would have your "overall"
star collection 'starData'. But your listbox itemssource would be bound to something like this:
public ICollectionView FilteredStars
{
get
{
ICollectionView source = CollectionViewSource.GetDefaultView(starData);
source.Filter = new Predicate<object>(FilterStars);
return source;
}
}
the logic that does the filtering here:
private bool FilterStars(object item)
{
bool b = false;
star a = item as star;
if (a != null)
{
if (a.Name.Contains(searchBoxText)) //your filter logic here
{
b = true;
}
else if String.IsNullOrWhiteSpace(searchBoxText)
{
b = true;
}
}
return b;
}
Basically, you have your main collection, then some logic that filters your main collection to a filtered collection, and that's what you should set itemssource of your listbox to. This, so far, is assuming you are going to put some kind of property change into your search text box and probably then click a button, like "Search" to then tell the list to check and re-populate to match the search term.
This is how I filter in a similar application
public IEnumerable<string> PastEntries1
{
get
{
if(string.IsNullOrEmpty(textValue))
{
return FieldDefString.PastEntries;
}
else
{
return FieldDefString.PastEntries.Where(x => x.StartsWith(textValue, StringComparison.OrdinalIgnoreCase));
}
}
}
i am working on an software in which i want to clear each thing after doing achieving a specific task, like clearing all the fields, list view etc etc and i've to write the a lot of things to be cleared off, like the code of my new button is:
private void btnNew_Click(object sender, EventArgs e)
{
txtProductCode1.ReadOnly = false;
txtInvoiceNo.ReadOnly = false;
cmbCustoemerType.Enabled = false;
cmbCustomerName.Enabled = false;
button1.Enabled = true;
txtProductCode1.Text = null;
txtWageName.Text = null;
txtWageCost.Text = null;
btnFirst.Visible = false;
btnPrevious.Visible = false;
btnNext.Visible = false;
btnLast.Visible = false;
cmbProductName.Enabled = true;
txtQty.ReadOnly = false;
txtPercant.ReadOnly = false;
txtDiscount.ReadOnly = false;
cmbCustoemerType.Enabled = true;
cmbCustomerName.Enabled = true;
button5.Enabled = true;
btnDelete.Enabled = true;
dtp1.Enabled = true;
btnSave.Text = "&Save";
cmbCustoemerType.Text = null;
cmbCustomerName.Text = null;
txtInvoiceNo.Clear();
txtDiscount.Clear();
txtGrandTotal.Clear();
txtProductName.Clear();
txtSalePrice.Clear();
txtQty.Clear();
txtTotal.Clear();
txtExtraWages.Text = null;
lvExtraWages.Items.Clear();
lvTransaction.Items.Clear();
lblCount.Text = null;
lblNetTotal.Text = null;
txtPercant.Text = null;
txtInvoiceNo.Text = invoice.ToString();
}
is there any way to get rid of writing the code again n again, like i need to enable one thing which i've disabled here on another button so i have to write reverse code of this to achieve the task and it's really annoying! is there any other way to do this?
EDIT:
tried following code:
private void btnNew_Click(object sender, EventArgs e)
{
//using setboxdefault function
SetTextBoxDefaults();
cmbCustoemerType.Text = null;
cmbCustomerName.Text = null;
cmbCustoemerType.Enabled = false;
cmbCustomerName.Enabled = false;
cmbProductName.Enabled = true;
cmbCustoemerType.Enabled = true;
cmbCustomerName.Enabled = true;
button5.Enabled = true;
btnDelete.Enabled = true;
button1.Enabled = true;
btnFirst.Visible = false;
btnPrevious.Visible = false;
btnNext.Visible = false;
btnLast.Visible = false;
btnSave.Text = "&Save";
lvExtraWages.Items.Clear();
lvTransaction.Items.Clear();
lblCount.Text = null;
lblNetTotal.Text = null;
dtp1.Enabled = true;
txtInvoiceNo.Text = invoice.ToString();
}
private void SetTextBoxDefaults()
{
var textBoxes = GetControls(this, typeof(TextBox));
foreach (var textBox in textBoxes)
{
TextBox.Clear();
}
}
public IEnumerable<Control> GetControls(Control control, Type type)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetControls(ctrl, type)).Concat(controls).Where(c => c.GetType() == type);
}
but it's giving error on TextBox.Clear(); , error is Error 4
An object reference is required for the non-static field, method, or property 'System.Windows.Forms.TextBoxBase.Clear()'
Please let me know where i am mistaking..!!
As Tim has suggested, you can iterate though the controls and set each one accordingly..
public IEnumerable<Control> GetControls(Control control,Type type)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetControls(ctrl,type)).Concat(controls).Where(c => c.GetType() == type);
}
private void btnNew_Click(object sender, EventArgs e)
{
SetComboBoxDefaults();
SetTextBoxDefaults();
SetButtonDefaults();
}
private void SetComboBoxDefaults()
{
var comboBoxes = GetControls(this, typeof(ComboBox));
foreach (var comboBox in comboBoxes)
{
((ComboBox)comboBox).Enabled = false;
((ComboBox)comboBox).Text = null;
}
}
private void SetTextBoxDefaults()
{
var textBoxes = GetControls(this, typeof(TextBox));
foreach (var textBox in textBoxes)
{
((TextBox)textBox).Clear();
}
}
private void SetButtonDefaults()
{
var buttons = GetControls(this, typeof(Button));
foreach (var button in buttons)
{
((Button)button).Visible = false;
if (button.Name == "btnSave") ((Button)button).Text = "&Save";
}
}
You can also have separate GetControl methods so that it returns a specific type of Control, reducing the need to cast to derived types.
update for edit:
You are using the TextBox type instead of the variable name in the foreach loop. Update it to use textBox (lowercase), not TextBox (pascal) see below:
private void SetTextBoxDefaults()
{
var textBoxes = GetControls(this, typeof(TextBox));
foreach (var textBox in textBoxes)
{
((TextBox)textBox).Clear();
}
}
Remember to stay DRY
Don't
Repeat
Yourself
Partition the reset logic into suitable, small methods that reset a logical grouping of controls. Then invoke those methods where and as needed.
What I have done in several such cases is this:
void SetTextBoxReadOnly(bool val, param TextBox[] textBoxes)
{
if(textBoxes != null && textBoxes.Length > 0)
{
foreach(TextBox textBox in textBoxes)
{
if(textBox != null)
{
textBox.ReadOnly = val;
}
}
}
}
void SetControlEnabled(bool val, param Control[] ctrls)
{
if(ctrls != null && ctrls.Length > 0)
{
foreach(Control ctrl in ctrls)
{
if(ctrl != null)
{
ctrl.Enabled = val;
}
}
}
}
// etc set of methods for similar situations.
// there methods can be invoked as
...
...
...
SetTextBoxReadOnly(true, txtProductCode1,
txtInvoiceNo,
txtQty,
txtPercant,
txtDiscount);
i am using telerik control(data grid view) in my project. but when i want to add new row in data grid, the text of previous rows (bindingSourceService.DataSource = dtservice , bindingSourceUnit.DataSource = dtunit) disappear.
my datagridview has 3 combobox column.
what is wrong? please help me.
my codes:
public void FactorLoad(object sender, EventArgs e)
{
try
{
var cb = new CategoriBll();
DataTable dtcategori = cb.GetAllDataCategori();
bindingSourceCategouri.DataSource = dtcategori;
}
catch (Exception ex)
{
ExceptionkeeperBll.LogFileWrite(ex);
}
}
private void DataGridViewFactorCellValueChanged(object sender, GridViewCellEventArgs e)
{
try
{
var row = DataGridViewFactor.CurrentRow;
if ((row != null) && (row.Cells[0].IsCurrent))
{
var categoryId = Convert.ToInt32(DataGridViewFactor.CurrentRow.Cells[0].Value);
var sb = new CategoriOptionBll();
DataTable dtservice = sb.ServiceGetById(categoryId);
bindingSourceService.DataSource = dtservice;
}
if ((row != null) && (row.Cells[1].IsCurrent))
{
var serviceId = Convert.ToInt32(DataGridViewFactor.CurrentRow.Cells[1].Value);
var cbi = new CostBll();
var dtunit = cbi.CostById(serviceId);
bindingSourceUnit.DataSource = dtunit;
}
}
catch (Exception ex)
{
ExceptionkeeperBll.LogFileWrite(ex);
}
}
private void DataGridViewFactorCellEditorInitialized(object sender, GridViewCellEventArgs e)
{
try
{
var row = DataGridViewFactor.CurrentRow;
if ((row != null) && (row.Cells[0].IsCurrent))
{
var categoryId = Convert.ToInt32(DataGridViewFactor.CurrentRow.Cells[0].Value);
var sb = new CategoriOptionBll();
DataTable dtservice = sb.ServiceGetById(categoryId);
bindingSourceService.DataSource = dtservice;
}
if ((row != null) && (row.Cells[1].IsCurrent))
{
var serviceId = Convert.ToInt32(DataGridViewFactor.CurrentRow.Cells[1].Value);
var cbi = new CostBll();
var dtunit = cbi.CostById(serviceId);
bindingSourceUnit.DataSource = dtunit;
}
}
catch (Exception ex)
{
ExceptionkeeperBll.LogFileWrite(ex);
}
}
It will disappear because there will be only 1 value in the data source. Try adding value to the data source rather then assigning single value.