Xtragrid SelectionChanged or Alternative - winforms

I'm having an issue here.
I have a XtraGrid in winforms with a multiselect mode true, I need to validate if the row I'm selecting, if it matches a condition, select it, if not, deselect it. I'm currently using the SelectionChanged method like this:
private void grdProducts_SelectionChanged(object sender, DevExpress.Data.SelectionChangedEventArgs e)
{
try
{
GridView view = sender as GridView;
int[] selectedRows = view.GetSelectedRows();
for (int i = 0; i < selectedRows.Length; i++)
{
if (view.IsRowSelected(selectedRows[i]))
{
Product product = view.GetRow(selectedRows[i]) as Candidato;
ProcessStatus processStatus = _procesoStatusService.GetProduct(product.IdProduct);
if (processStatus.Proccess.Inventory == (int)ProductInventory.Yes)
{
view.UnselectRow(selectedRows[i]);
XtraMessageBox.Show("One or more products are currently in inventory.");
}
}
}
}
catch (Exception)
{
throw;
}
}
The problem here is when the code reaches the view.UnselectRow(selectedRows[i]); line, the SelectionChanged method is called again and the program send multiple XtraMessageBox.
Any help?

You must use BaseView.BeginSelection method before your code and BaseView.EndSelection method after your code. This will prevent the ColumnView.SelectionChanged event to raise.
Here is example:
private void grdProducts_SelectionChanged(object sender, DevExpress.Data.SelectionChangedEventArgs e)
{
var view = sender as GridView;
if (view == null) return;
view.BeginSelection();
try
{
int[] selectedRows = view.GetSelectedRows();
for (int i = 0; i < selectedRows.Length; i++)
{
if (view.IsRowSelected(selectedRows[i]))
{
Product product = view.GetRow(selectedRows[i]) as Candidato;
ProcessStatus processStatus = _procesoStatusService.GetProduct(product.IdProduct);
if (processStatus.Proccess.Inventory == (int)ProductInventory.Yes)
{
view.UnselectRow(selectedRows[i]);
XtraMessageBox.Show("One or more products are currently in inventory.");
}
}
}
}
catch (Exception)
{
view.EndSelection();
throw;
}
view.EndSelection();
}

Related

object reference not set for DataView from gridivew.DataSource as DataView

I have method validatingeditor to validate for duplicate
private void GridView1_ValidatingEditor(object sender, DevExpress.XtraEditors.Controls.BaseContainerValidateEditorEventArgs e)
{
GridView view = sender as GridView;
DataView currentDataView = view.DataSource as DataView;
if (view.FocusedColumn.FieldName == "Sequence")
{
//check duplicate code
string currentCode = e.Value.ToString();
for (int i = 0; i < currentDataView.Count; i++)
{
if (i != view.GetDataSourceRowIndex(view.FocusedRowHandle))
{
if (currentDataView[i]["Sequence"].ToString() == currentCode)
{
e.ErrorText = "Duplicate Code detected.";
e.Valid = false;
break;
}
}
}
}
}
But it says object reference not set which the problem is at DataView currentDataView = view.DataSource as DataView;
But I do not understand why.
I was populating my gridcontrol with the ado entity dataset. so after calling adapter.Fill(dataset). I also have to write gridcontrol.DataSource=dataset;

XAM Data Grid change order of filter drop down list

Can I change the order of filter drop down list.
There is a blank option at the end of the list I've to put it at very first position.
To solve this I searched for the TreeView that is being displayed and reassociate the ItemSource at runtime. I have used RecordFilterDropDownOpening event of XAMDataGrid.
CODE:
void DataPresenter_RecordFilterDropDownOpening(object sender, Infragistics.Windows.DataPresenter.Events.RecordFilterDropDownOpeningEventArgs e)
{
RecordFilterTreeControl rftc = null;
try
{
rftc = (e.MenuItems[e.MenuItems.Count - 1] as FieldMenuDataItem).Header as RecordFilterTreeControl;
if (rftc != null)
{
rftc.Loaded += new RoutedEventHandler(rftc_Loaded);
}
}
catch (Exception ex)
{
LogInfo.LogToListeners(ex);
}
finally
{
rftc = null;
}
}
void rftc_Loaded(object sender, RoutedEventArgs e)
{
TreeView tv = null;
try
{
tv = Infragistics.Windows.Utilities.GetDescendantFromType(sender as DependencyObject, typeof(TreeView), false) as TreeView;
if (tv != null)
{
var newSource = new ObservableCollection<RecordFilterTreeItem>();
foreach (var item in tv.ItemsSource)
{
if (item is RecordFilterTreeItem)
{
newSource.Add(item as RecordFilterTreeItem);
}
}
if (newSource[newSource.Count - 1].DisplayText == "(Blanks)")
{
newSource.Move(newSource.Count - 1, 1);
}
tv.ItemsSource = newSource;// this will give a new itemsource to treeview
}
}
catch (Exception ex)
{
LogInfo.LogToListeners(ex);
}
finally
{
tv = null;
}
}
Result:

RepositoryItemCheckEdit doesn't stay checked

I try to add a RepositoryItemCheckEdit to my GridView using devexpress and Winforms. However, I can get only one checkbox be checked. If I check another one, the checkbox I checked before becomes unchecked. I followed everything I can find on the net, but couldn't make this work. What am I missing?
The code part I insert the column:
gcIsEmirleri.DataSource = (from i in isemirleri
select new
{
ID = i.isEmriId,
// other attributes
}).ToList();
GridColumn column = gvIsEmirleri.Columns["Sec"];
if (column == null)
{
gvIsEmirleri.BeginUpdate();
DataColumn col = new DataColumn("Sec", typeof(bool));
column = gvIsEmirleri.Columns.AddVisible("Sec");
col.VisibleIndex = 0;
col.Caption = "Sec";
col.Name = "Sec";
col.OptionsColumn.AllowEdit = true;
gvIsEmirleri.EndUpdate();
gvIsEmirleri.Columns["Sec"].UnboundType = DevExpress.Data.UnboundColumnType.Boolean;
RepositoryItemCheckEdit chk = new RepositoryItemCheckEdit();
chk.ValueChecked = true;
chk.ValueUnchecked = false;
gvIsEmirleri.Columns["Sec"].ColumnEdit = chk;
chk.QueryCheckStateByValue += chk_QueryCheckStateByValue;
}
The code part I make the checkbox two-stated instead of three:
private void chk_QueryCheckStateByValue(object sender, DevExpress.XtraEditors.Controls.QueryCheckStateByValueEventArgs e)
{
if (e.Value == null)
{
e.CheckState = CheckState.Unchecked;
e.Handled = true;
}
}
EDIT: I created a List<bool> chkList; and do the following operations:
This function is added to checkedits' CheckStateChanged:
private void chk_CheckStateChanged(object sender, EventArgs e)
{
CheckEdit chk = sender as CheckEdit;
if (chk.Checked)
chkList[gvIsEmirleri.FocusedRowHandle] = true;
else
chkList[gvIsEmirleri.FocusedRowHandle] = false;
FillBindingSource();
}
In FillBindingSource I added the lines:
for (int i = 0; i < chkList.Count; i++)
{
if (chkList[i])
gvIsEmirleri.SetRowCellValue(i, "Sec", true);
}
I debug these lines, I see that List has correct bool values and gvIsEmirleri.SetRowCellValue(i, "Sec", true); is operated when it has to. However, it still doesn't work.
My guess is : You are using an unbound Column, and you are not saving the checked / unckecked info, so, after the selected row is left, the checkBox get it's initial value (unckecked).
For this, I suggest you handle the CustomUnboundColumnData event of your view. Here is a simple :
readonly Dictionary<object, bool> checkedMap = new Dictionary<object, bool>();
private void viewScales_CustomUnboundColumnData(object sender, CustomColumnDataEventArgs e)
{
// Check what column
if (e.Column != gvIsEmirleri.Columns["Sec"])
return;
if (e.IsGetData)
{
// check if the row has been checked and set it's value using e.Value
bool checked;
if (checkedMap.TryGetValue(e.Row, out checked))
e.Value = checked;
}
if (e.IsSetData)
{
var checked = Convert.ToBoolean(e.Value);
// Check if the key already exist
if (checkedMap.ContainsKey(e.Row))
scaleMap.Remove(e.Row);
checkedMap.Add(e.Row, checked);
}
}
Note : This is the way I resolved a similar problem, but I did not test the code I just wrote.

how to make a Custom CheckButton on TileContainer checked false DevExpress

I have a CheckButton on TileContainer.
I showed a PopUp Menu on Checked Event of CheckButton.
Now, I need to Uncheck that CheckButton at the end of the event.
this.tileContainer1.Buttons.AddRange(new DevExpress.XtraEditors.ButtonPanel.IBaseButton[] {
new DevExpress.XtraBars.Docking2010.WindowsUIButton("ShowList", global::DMS.Properties.Resources.speech_bubble, -1, DevExpress.XtraBars.Docking2010.ButtonStyle.CheckButton, 0)});
If I understand your scenario correctly, you can use the following approch:
WindowsUIButton checkButton = new WindowsUIButton()
{
Caption = "Check Button",
Style = ButtonStyle.CheckButton
};
checkButton.CheckedChanged += checkButton_CheckedChanged;
tileContainer1.Buttons.Add(checkButton);
//...
int reentranceCount = 0;
void checkButton_CheckedChanged(object sender, EventArgs e) {
if(reentranceCount > 0) return;
/*do some stuff */
Uncheck((WindowsUIButton)sender);
}
void Uncheck(WindowsUIButton button) {
reentranceCount++;
try {
button.Checked = false;
}
finally { reentranceCount--; }
}
Update:
If you are using the TileContiner.ButtonChecked event you should update the code above as follows:
//...
tileContainer1.ButtonChecked += tileContainer_ButtonChecked;
//...
void tileContainer_ButtonChecked(object sender, ButtonEventArgs e) {
if(reentranceCount > 0) return;
/*do some stuff */
Uncheck((WindowsUIButton)e.Button);
}

Updating UI from a background thread which is called in a loop in main UI when the thread finishes

I have a WinForms application that is calling a business class method that performs some heavy duty action taking about 5 seconds for each call. The main form calls this method in a loop. This loop can run from 10 times to maybe up to 10 thousand times.
The WinForms application sends a parameter to the business class and has an area to display the time taken for each method call and what the value returned by the method. How do I inform my main window and update a text area in the main winform with what the method has returned for each call?
Currently the data comes all at once after all the threads have finished. Is there a way to update the UI for all the iterations of the loop once the each call is done? I don't mind if it is done sequentially also.
The FORM
HeavyDutyClass hd;
public Form1()
{
InitializeComponent();
hd = new HeavyDutyClass();
}
//BUTTON CLICK
private void Start_Click(object sender, EventArgs e)
{
int filecount = 5000; //BAD - opening 5000 threads! Any other approach?
hd.FileProcessed += new EventHandler(hd_FileProcessed);
var threads = new Thread[filecount];
for (int i = 0; i < filecount; i++)
{
threads[i] = new Thread(() => { hd.LongRunningMethod(); });
threads[i].Start();
}
}
//BUSINESS CLASS EVENT THAT FIRES WHEN BUSINESS METHOD COMPELTES
void hd_FileProcessed(object sender, EventArgs e)
{
if (dgv.InvokeRequired)
{
dgv.Invoke((MethodInvoker)delegate { UpdateGrid(); });
}
}
private void UpdateGrid()
{
dgv.Rows.Add(1);
int i = dgv.Rows.Count;
dgv.Rows [ i-1].Selected = true;
dgv.FirstDisplayedScrollingRowIndex = i - 1;
}
The business HeavyDuty class
public event EventHandler FileProcessed;
public HeavyDutyClass()
{
}
protected virtual void OnMyEvent(EventArgs e)
{
if (FileProcessed != null)
{
FileProcessed(this, e);
}
}
public bool LongRunningMethod()
{
for (double i = 0; i < 199990000; i++)
{
//time consuming loop
}
OnMyEvent(EventArgs.Empty);
return true;
}
Add a Winforms Project, Drop a Label Control on the Form , Copy-Paste this code and Hit F5
[EDIT]: Updated with the business class comment from the user
NB: My form class is named Form3. You may have to change your Program.cs or vice-versa.
using System.ComponentModel;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class BusinessClass
{
public int MyFunction(int input)
{
return input+10;
}
}
public partial class Form3 : Form
{
private BackgroundWorker _worker;
BusinessClass _biz = new BusinessClass();
public Form3()
{
InitializeComponent();
InitWorker();
}
private void InitWorker()
{
if (_worker != null)
{
_worker.Dispose();
}
_worker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
_worker.DoWork += DoWork;
_worker.RunWorkerCompleted += RunWorkerCompleted;
_worker.ProgressChanged += ProgressChanged;
_worker.RunWorkerAsync();
}
void DoWork(object sender, DoWorkEventArgs e)
{
int highestPercentageReached = 0;
if (_worker.CancellationPending)
{
e.Cancel = true;
}
else
{
double i = 0.0d;
int junk = 0;
for (i = 0; i <= 199990000; i++)
{
int result = _biz.MyFunction(junk);
junk++;
// Report progress as a percentage of the total task.
var percentComplete = (int)(i / 199990000 * 100);
if (percentComplete > highestPercentageReached)
{
highestPercentageReached = percentComplete;
// note I can pass the business class result also and display the same in the LABEL
_worker.ReportProgress(percentComplete, result);
_worker.CancelAsync();
}
}
}
}
void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
// Display some message to the user that task has been
// cancelled
}
else if (e.Error != null)
{
// Do something with the error
}
}
void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = string.Format("Result {0}: Percent {1}",e.UserState, e.ProgressPercentage);
}
}
}
With this you can achieve Cancel functionality also very easily.
Observe that during initialisation, I set the WorkerSupportsCancellation = true & then I check for _worker.CancellationPending in the DoWork. So, if you want to cancel the process by a Cancel Button click, then you will write this code in the button handler- _worker.CancelAsync();

Resources