passing control indexer by reference to method to change its property - methods

i have made a program, which include a lot of controls. The controls would be showed and hided according to the choice of the user. That means that controls overlapped on each other at design time. now i want to change the forecolor and backcolor of all controls at design time. but i founded so hard to accomplish this task, because all the control overlapping each other. so I decided to make a for loop method to iterate the controls in the form and then check each control in turn whether it has controls. when the control has also controls in it, I call the same method and pass the control to it to change the properties for the subcontrols too. The method like so:
void setColor(ref Control con)
{
con.BackColor= System.Drawing.Color.Black;
con.ForeColor=System.Drawing.Color.Yellow;
if (con.Controls.Count > 0) { setColor(ref con); }
}
so my Form include tabControl with multiple tabPages. I iterate the tabPages and wanted to pass it to this method, but I become error "Indexer may not be passed as an out or ref parameter"
I pass it so: setColor(ref tabControl1.Controls[i]);
can you please help me to solve this problem?

I have resolved the problem.
I have removed the "ref" from method and wrote the method simply like the following:
void SetColor(Control con)
{
con.BackColor = System.Drawing.Color.Black;
con.ForeColor = System.Drawing.Color.Yellow;
if (con.Controls.Count > 0)
{
for (int i=0; i<con.Controls.Count;i++)
SetColor(con.Controls[i]);
}
}
and call it so: setColor(this.Controls[i]);

Related

Implementing multiple dialogs with similar processing

We have multiple dialogs in our MFC program that are very similar. Each one of these dialogs contain similar controls (i.e., they all contain a name, date, address, etc). Because of this, we've had to code out the display code multiple times for the windows despite the fact that the processing of these controls is identical. I'm looking for suggestions on how to change up our guis so that i have to only do the processing at one spot and not have to do it multiple times.
My thought was to have a class that would do the processing and pass pointers to the controls to display to that class, though i feel that is not a very good OO design.
Thoughts?
Create a base class derived from CDialog (say CMyDlgBase), place all your common functions there and derive your dialog classes from CMyDlgBase instead of CDialog.
You can now call the functions in CMyDlgBase as if they were declared directly in your dialog classes.
EDIT sample code to validate an item common to dialogs (CDlg1 and CDlg2 are derived from CMyDlgBase), error checking code not included:
BOOL CMyDlgBase::ValidateName(UINT nID)
{ CString ss;
CEdit *pEdit = GetDlgItem(nID);
pEdit->GetWindowText(ss);
if (ss.Find(_T("A")) < 0) // some kind of validation
{ MessageBox(_T("Name should contain the character 'A'"));
pEdit->SetFocus();
return FALSE;
}
return TRUE;
}
CDlg1::OnOK()
{ if (!ValidateName(IDC_DLG1_NAME)) // resource id value = 101
return;
CDialog::OnOK(); // This will close the dialog and DoModal will return.
}
CDlg2::OnOK()
{ if (!ValidateName(IDC_DLG2_NAME)) // resource id value = 102
return;
CDialog::OnOK(); // This will close the dialog and DoModal will return.
}

Mvvm - Updating Binding takes too long

I have a 5 ViewModels. Every view has their own VM. When I start the program, the ViewModel changes the bindings, i.e.
private string _bruttolohn;
public string Bruttolohn
{
get { return _bruttolohn; }
set
{
if (value != null)
{
if (value != _bruttolohn)
{
_bruttolohn = value;
Calculate();
RaisePropertyChanged(() => Bruttolohn);
}
}
}
}
Bruttolohn = some value I put in to calculate and set the new values. I have ~100 other propertys, which are all using Binding. If I start the program, the calculation is fine and works fast! But when I change the View (All views are in a ContentControl. If I click on a button, the view is being changed like this: MyContent.Content = new FirstView();). Now here's the problem: If I change the view ~30 times, the ViewModel needs way too long to set the bindings. Why!?
+ If I debug and I'm at this point:
RaisePropertyChanged(() => Bruttolohn);
Error pops up: ObservableObject.cs is missing...?
There is nothing wrong with the code you've shown so I suspect the Calculation method. Profile it.
If the Calculation() method is too long to post, it shouldn't be in a property setter :)
I guess I found the solution. Every time I click on the button "FirstView", the Content of the ContentControl gets a NEW VIEW()! So every time I click on the button, it'll do:
MyContent.Content = new FirstView();
This means that there are still somehow Views in the background open... I can't explain it by myself, but if I set the View globally like
FirstView fw;
and say in the constructor of the MainViewModel
fw = new FirstView();
I can easily assign the content of my ContentControl like this (without creating a new View):
MyContent.Content = fw;
You can download a test app here: http://www65.zippyshare.com/v/89159114/file.html
It has a MainView and 2 Views. It shows my problem. If you click on the Button "FirstView", the content of the contentcontrol will be "FirstView.xaml". It has 2 textboxes, which calculate the sum and has a for-loop (for i = 0, i < 500, i++). If you calculate right at the start, the calculation takes only ~1 sec, but if you click the Button "FirstView" ~30 times and try to calculate again, the calculation takes more than 10 sec!!!
I thinks it's because of MyContent.Content = new FirstView(); You can check my program and correct me if I'm wrong or say if I'm right... Like I said, I think that this is the solution, but I'm not 100% sure.
if Calculate() isn't an async method, it blocks the UI.
You could use
Task.Run(() =>
{
Calculate();
RaisePropertyChanged(() => Bruttolohn);
});
Not relevant to your question, but maybe interesting:
if (value != _bruttolohn)
Strings should be compared using .Equals, as the same string can be referenced to different places in the heap.
So:
if (value == null || !value.Equals(_bruttolohn))

Edit Control not updating with Spin Control MFC

I am trying to use an edit control along with a spin control using MFC visual studio .net 2003. I have carried out the basic settings for the spin control like setting the "AutoBuddy" property and "SetBuddyInteger" property to True so that the Spin control works in coordination with the edit control next to it. In my Spin control's event handler, I am facing a problem when I am trying to call my Invalidate() function. The float value in my edit control does not update and stays zero. If I remove the Invalidate(), then the value increments but my paint function is not updated obviously. A code of the following is given below:
void CMyDlg::OnSpinA(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
// TODO: Add your control notification handler code here
UpdateData();
m_A = m_ASpinCtrl.GetPos(); // m_A is my edit control float value variable
Invalidate(); // Invalidate is to be called to update my paint function to redraw the drawing
UpdateData(false);
*pResult = 0;
}
I have carried out the tab order correctly as well for the two controls.
Any suggestions on where I am going wrong?
Thanks in advance.
If you just want to have a spinning integer, you don't have to override anything.
The spin control has to be right next to the edit control in the tab order. With AutoBuddy that's all you have to do.
m_A when getting the position back would do something weird and would not return you the correct value. Try using the pointer to get your position and value and then carry out the invalidate().
{
LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
// TODO: Add your control notification handler code here
UpdateData();
CString tempStr;
m_A += pNMUpDown->iDelta;
tempStr.Format("%f",m_A);
m_ACtrl.SetWindowText(tempStr); // Like a CEdit m_ACtrl to display your string
Invalidate();
UpdateData(false);
*pResult = 0;
}
This should work perfectly well. Let me know if you still get any problems.

How to redirect a WM_KEYDOWN message to another control in MFC?

I'm on a roll today with MFC! :D
I have a text box and a list view control.
When the user presses the VK_UP and VK_DOWN keys in the text box, I would like this to happen:
Do some stuff.
Have the list view control also process the message (to highlight the previous/next item).
I want the list view to wrap around the current selection, if the key press is the first in its sequence.
Do some more stuff.
I tried subclassing my edit box in my dialog:
class MyEditBox : public CWnd
{
bool allowWrap;
afx_msg void OnKeyUp(UINT, UINT, UINT) { this->allowWrap = true; }
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CListCtrl &listView = static_cast<CListView *>(
this->GetParent()->GetDlgItem(IDC_LIST_VIEW))->GetListCtrl();
if (nChar == VK_UP || nChar == VK_DOWN)
{
int iSelBefore = listView.GetNextItem(-1, LVNI_SELECTED);
this->GetParent()->GetDlgItem(IDC_LIST_VIEW)
->OnKeyDown(nChar, nRepCnt, nFlags); //Oops! Protected member :(
int iSelAfter = listView.GetNextItem(-1, LVNI_SELECTED);
if (iSelBefore == iSelAfter && // Did the selection reach an end?
this->allowWrap) // If so, can we wrap it around?
{
int i = a == 0 ? listView.GetItemCount() - 1 : 0;
listView.SetItemState(i, LVIS_SELECTED | LVIS_FOCUSED,
LVIS_SELECTED | LVIS_FOCUSED);
}
}
this->allowWrap = false;
}
}
but OnKeyDown() is a protected member, so I can't just call it on another control.
Is there a better way to solve this than manually sending the command with SendMessage? Should I change my design, e.g. subclass something else, etc.?
Your intention is to select previous or next item in list control, right? Then you should call the method to do that directly instaed of asking the CListCtrl to "process" your message.
You may call CListCtrl::SetSelectionMark and CListCtrl::SetItemState to select next or previous keystroke. Example:
cListCtrl.SetSelectionMark(nIndex);
cListCtrl.SetItemState(nIndex, LVIS_SELECTED | LVIS_FOCUSED, 0xFF);
You can handle Key Down, Key Up as well as Page Down, Page Up, End, Home or any any key from edit box. You need to do calculation, though.
Or you can just SendMessage. There is no need to call OnKeyDown directly. Let the framework call it for you when you send the message.
I am seeing also other ways to solve this:
Derive a class from CListCtrl called MyListCtrl and choose one of two things:
1.1 Declare MyEditBox as a friend and now you can call the protected methods on MyEditBox
1.2 Add public methods CallOnKeyDown(...) and CallOnKeyup(...) to it that only do what is needed.
And when creating the control, instance a MyListCtrl instead of a CListCtrl. Also replace the listView variable you have shown here to be a MyListCtrl and use the methods you have now available
Use PreTranslateMessage(...). I think this "hammer" solution is worse than sending a message.

MVP - Showing/hiding controls based on business logic

What would be the best way of going about this? I have a method in the presenter that populates various textboxes using a switch statement, but also needs to make sure that only these textboxes are visible, eg.:
switch (operation.CalculationType) {
case CalcType.Type1:
textbox1.Visible = true
_view.TextBox1 = "some value";
break;
case CalcType.Type2:
textbox1.Visible = true;
textbox2.Visible = true;
_view.TextBox1 = "some value";
_view.TextBox2 = "another value";
break;
I'm not fond of the idea of exposing a Visible property for each control on the form (theoretically this could lead to exposing all sorts of properties, which just seems wrong to me). Another idea I had was to create a method or event that the presenter calls, telling the form to show/hide the controls, but that kind of means replicating the logic in the presenter.
So what's the "proper" way of doing something this?
Thanks
If the variable _view is not an interface you should make it one, implement it and then add a method or methods that setup which textboxes are visible. This way it is clear in the code what you are trying to do and it not tied to that particular form implementation.
Inteface IFormView
Sub DisplayType1
Sub DisplayType2
....
End Interface

Resources