I have a DataGridView with custom DataGridViewComboBoxCell columns, and I run the following code to initiaize it's cells to the initial value I want:
try
{
this.dgvTemplatesConfiguration.Columns.Add(this.CreateFaultsColumn(faultsData, "OuterFaults", 2));
this.dgvTemplatesConfiguration.Columns.Add(this.CreateFaultsColumn(faultsData, "InnerFaults", 5));
}
catch (Exception ex)
{
Log.WriteLineIf(ex.Message, TraceLevel.Info);
throw;
}
for (int i = 0; i < dgvTemplatesConfiguration.Rows.Count - 1; i++)
{
dgvTemplatesConfiguration["InnerFaults", i].Value = OkFaultName;
dgvTemplatesConfiguration["OuterFaults", i].Value = OkFaultName;
}
If I do it on OnLoad event, the code works fine and inits the cells, but if I run it afterwards on OnVisibleChanged event, I get an exception
DataGridViewComboBoxCell value is not valid
What is the proper way of setting default values on DataGridViewComboBoxCell?
Related
I have created for loop but it only executes once instead of multiple times. At first it takes value but after increment ment it doesnot executes but catch an exception of array out of bounds and indexoutofexception.
Why this for loop is not repeating, I can't seem to find its solution.
This is my code
private void CheckForVariable()
{
//to split parameter by , then stored in array
parameter = inputcommand[1].Split(",".ToCharArray());
for (int i = 0; i < parameter.Length ; i++)
{
try
{
//checks if the parameter is an int
int test = Convert.ToInt32(parameter[i]);
//Console.WriteLine(parameter[i]);
}
catch
{
Boolean foundVariable = false;
if (foundVariable == false)
{
foreach (KeyValuePair<string, int> variable in VariableDictionary)
{
if (variable.Key.Equals(parameter[i]))
{
parameter[i] = variable.Value.ToString();
}
}
}
}
}
}
I tried to do exception handling using try catch, it doesnot seems to work. It is only taking single value instead of multiple times. I want to pass repeated value until it executes as expected.
I have a grid view contains multiple columns and I adjusted their input type to be double.
When the user selects a cell, enters its data, I want to check if it matches the type of double.
If the user clicks on another cell and the one he is about to leave doesn't match and it failed in parsing, I want the focus return to the failed cell, and not moving to the new selected one, to force the user to enter a valid data before continuing filling the rest of the cells.
The problem is that it always leaves the failed cell. Even when I used other functions like validating or validated.
Here is my code sample:
private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e)
{
var selectedCell = dataGridView1.SelectedCells[0];
if (selectedCell.OwningColumn.ValueType == typeof(double))
{
try
{
double result = Convert.ToDouble(selectedCell.EditedFormattedValue.ToString());
if (result <= 0)
{
MessageBox.Show("Please Positive Numbers Only");
dataGridView1.Focus();
dataGridView1.CurrentCell = dataGridView1.Rows[selectedCell.RowIndex].Cells[selectedCell.ColumnIndex];
dataGridView1.BeginEdit(true);
}
else
{
dataGridView1.CurrentCell.Value = result;
}
}
catch
{
MessageBox.Show("Please Enter Numbers Only");
}
}
}
You can use event DataGridView.CellValidating. This should fix your problem.
Example:
private void dataGridView1_CellValidating(object sender,
DataGridViewCellValidatingEventArgs e)
{
if (e.ColumnIndex == 1) // 1 should be your column index
{
int i;
if (!int.TryParse(Convert.ToString(e.FormattedValue), out i))
{
e.Cancel = true;
label1.Text ="please enter numeric";
}
else
{
// the input is numeric
}
}
}
DataGridView.CellValidating Event
How to: Validate Data in the Windows Forms DataGridView Control
CellValueChanged vs CellValidating Events for DataGridView
I´ve got a small issue with my textbox-event...
When entering a number everything works fine and the integer in the textbos is subtracted from my sum that i have as an property in another class, but when I am deleteing the same number the last singular refuses to be subtracted from my variable that is connected to a label. I have to write 0 in the textbox to set the my label to my property.
If someone could helt me out I would be really gretfull!
private void txtBoxDiscount_TextChanged(object sender, TextChangedEventArgs e)
{
try
{
if (inv.TotalAllItems > Int32.Parse(txtBoxDiscount.Text))
{
float temp = 0;
temp = inv.TotalAllItems - Convert.ToInt32(txtBoxDiscount.Text);
lblTotalAmount.Content = temp;
}
else
{
MessageBox.Show("Discount can not be greater than the total amount.\nPlease try again", "Something went wrong", MessageBoxButton.OK, MessageBoxImage.Hand);
txtBoxDiscount.Text = "";
lblTotalAmount.Content = inv.TotalAllItems;
}
}
catch
{
}
}
Put a breakpoint in the empty catch block. You'll find that Int32.Parse(txtBoxDiscount.Text) throws an exception when txtBoxDiscount.Text is an empty string. This is why you should never use an empty catch block.
Use Int32.TryParse() instead. If the text can't be parsed as a number, it will leave discount equal to zero.
private void txtBoxDiscount_TextChanged(object sender, TextChangedEventArgs e)
{
int discount = 0;
Int32.TryParse(txtBoxDiscount.Text, out discount);
if (inv.TotalAllItems > discount)
{
float temp = 0;
temp = inv.TotalAllItems - discount;
lblTotalAmount.Content = temp;
}
else
{
MessageBox.Show("Discount can not be greater than the total amount.\nPlease try again", "Something went wrong", MessageBoxButton.OK, MessageBoxImage.Hand);
txtBoxDiscount.Text = "";
lblTotalAmount.Content = inv.TotalAllItems;
}
}
If you want to treat a non-numeric string as an error, rather than as zero, Int32.TryParse() also returns false when the parse fails:
private void txtBoxDiscount_TextChanged(object sender, TextChangedEventArgs e)
{
int discount = 0;
if (!Int32.TryParse(txtBoxDiscount.Text, out discount))
{
// Do something else
}
else if (inv.TotalAllItems > discount)
{
In a MFC dialog, I have used a CListCtrl with checkbox. I want to disable multi checkbox selection , so that user can only select a single checkbox at a time. What is the best way to achieve this.I have done this
void SomeClass::OnClickList(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
int nSelectedItemIndex = -1;
nSelectedItemIndex = m_ListCtrl.GetNextItem(-1, LVNI_SELECTED);
int nCount = m_ListCtrl.GetItemCount();
for(int nItem = 0; nItem < nCount; nItem++)
{
m_ListCtrl.SetCheck(nItem,false);
}
if(nSelectedItemIndex != -1)
m_ListCtrl.SetCheck(nSelectedItemIndex,true);
*pResult = 0;
}
Somehow I think this method is not so proper and can be made better in other way. All suggesions are welcomed.
EDIT: UPDATE: after writing the code , everything is working but I am facing a new problem.
calling SetCheck() function inside OnItemChanged message handler function, it is calling the same function again, creating a recursion.Thus selection change is somehow slow. How to avoid this.Please help. ????
Finally I have solved it . Now the checkbox and selection works at par. selecting checkbox selects the row and vice versa and one selection is possible. the code:
void SomeClass::ResetAllCheckBox()
{
int nCount = m_ListCtrl.GetItemCount();
for(int nItem = 0; nItem < nCount; nItem++)
{
m_ListCtrl.SetCheck(nItem,false);
}
}
//Handler for ON_NOTIFY(NM_CLICK,...)
void SomeClass::OnClickList(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
NMLISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
LVHITTESTINFO hitinfo;
int nPosCB=-1,nPos=-1;
hitinfo.pt = pNMListView->ptAction;
//Make the hit test...
nPosCB = m_ListCtrl.HitTest(&hitinfo);
if(hitinfo.flags != LVHT_ONITEMSTATEICON)
return;
ResetAllCheckBox();
nPos = m_ListCtrl.GetNextItem(-1,LVNI_SELECTED);
m_ListCtrl.SetItemState(nPos, ~LVIS_SELECTED, LVIS_SELECTED);
m_ListCtrl.SetItemState(nPosCB, LVIS_SELECTED, LVIS_SELECTED);
m_ListCtrl.SetSelectionMark(nPosCB);
*pResult = 0;
}
//Handler for ON_NOTIFY(LVN_ITEMCHANGED,...)
void SomeClass::OnItemchangedList(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
int nPos = -1;
ResetAllCheckBox();
nPos = m_ListCtrl.GetNextItem(-1,LVNI_SELECTED);
if(nPos != -1)
m_ListCtrl.SetCheck(nPos);
int nCount = m_ListCtrl.GetItemCount();
int nSelectedItemIndex = -1;
for(int nItem = 0; nItem < nCount; nItem++)
{
if(m_ListCtrl.GetCheck(nItem)== 1)
nSelectedItemIndex = nItem;
}
*pResult = 0;
}
When creating the control make sure this style is used LVS_SINGLESEL.
It is passed in the CreateEx/CreateEx function. Also available from the resource editor (if control is added through it).
I found a shorter solution. The idea is to detect if the user checked a checkbox. If it is the case, unchecked all the other checboxes, otherwise do nothing. Contrary to the answer by #egur, this solution does not check the checkbox upon selection of the row.
static void DisableAllItemsExcept(CListCtrl& ctrl, int indexToKeepChecked)
{
for (int nItem = 0; nItem < ctrl.GetItemCount(); nItem++)
if (nItem != indexToKeepChecked)
ctrl.SetCheck(nItem, FALSE);
}
//in begin message map
//ON_NOTIFY(LVN_ITEMCHANGED, IDC_SC_LIST, &CMyDlg::OnLvnItemchangedScList)
void CMyDlg::OnLvnItemchangedScList(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
//detect if we checked a new element
if ( (pNMLV->uChanged & LVIF_STATE) && (pNMLV->uNewState & 0x2000) && (pNMLV->uOldState & 0x1000) )
DisableAllItemsExcept(m_lcList, pNMLV->iItem);
*pResult = 0;
}
The detection of state change was based on the following article : Get the notification code from Listview Control checkboxes. The values 0x1000 and 0x2000 do not seems to be defined anywhere in the header file, so maybe I'm using an undocumented feature.
I want to open some non model windows (WPF) but at the point that this has to happen I am on a non STA thread. So I start a new thread and open them on there. But as soon as the are opened they close again. (By the way. the behaviour of these windows should be independent from the mainwindow. So no owner property is set)
private void SomeMethod_OnA_NON_STA_Thread()
{
// some other work here
Thread ANewThread = new Thread(OpenSomeWindows);
ANewThread.SetApartmentState(ApartmentState.STA);
ANewThread.Start();
}
private void OpenSomeWindows()
{
TestWindow T;
for (int i = 0; i < 3; i++)
{
T = new TestWindow();
T.Show();
}
}
What am I doing wrong here?
If you want your windows to live, you have to start the message loop after you created them (otherwise your thread just exits, and the windows have no chance to render themselves):
private void OpenSomeWindows()
{
for (int i = 0; i < 3; i++)
{
TestWindow T = new TestWindow();
T.Show();
}
Dispatcher.Run(); // <---------
}
(In main thread, the message loop is created by the framework for you.)
P.S.: I am not sure whether the windows can be garbage collected, so I would keep references to them somewhere:
List<TestWindow> windows = new List<TestWindow>();
for (int i = 0; i < 3; i++)
{
TestWindow t = new TestWindow();
t.Show();
windows.Add(t);
}
Dispatcher.Run();
P.P.S.: Maybe you want your windows to run in the main thread? Actually you can do this. You need just the following:
private void SomeMethod_OnA_NON_STA_Thread()
{
// some other work here
Application.Current.Dispatcher.Invoke(OpenSomeWindows);
}
private void OpenSomeWindows()
{
for (int i = 0; i < 3; i++)
{
TestWindow T = new TestWindow();
T.Show();
}
// this way, no Dispatcher.Run is needed
}
The Thread dies at the end of the calling method. Make ANewThread into a field (declare it at the class/Form level).