How to avoid EN_CHANGE notifications when sending WM_SETTEXT?
You could disable (EnableWindow(FALSE)
or send WM_ENABLE
with param FALSE) the control prior to sending WM_SETTEXT
then enabling it afterwards. That should prevent the EN_CHANGE
There is probably some more elegant method :p
The way I've done it before (last time, like 20 minutes ago; in fact I was thinking about asking the same question), is by setting a flag. When I'm about to set the text programatically, I set the flag, and I check it in the EN_CHANGE handler:
void CMyDialog::MyFunction()
{
setEditTextProgramatically = true;
c_Edit.SetWindowText(_T("Whatever"));
setEditTextProgramatically = false;
}
void CMyDialog::OnEnChangeEdit()
{
if (!setEditTextProgramatically)
{
// Do whatever you need to do
}
}
I know it's not the most elegant solution, but it works, at least for me.
I've always wondered why MFC doesn't provide a way to distinguish user input from changes from code, but that's the way it is.
The below code uses a C++ 11 feature, but that can easily be changed.
HEADER
// CEditOptionalNotify.h
//
// CEdit derived class allowing the control's text value to be
// set without (optionally) causing EN_CHANGE processing.
//
#pragma once
class CEditOptionalNotify : public CEdit
{
//DECLARE_DYNAMIC(CEditOptionalNotify)
// Enable use of RUNTIME_CLASS macro and CObject::IsKindOf()
public:
CEditOptionalNotify();
virtual ~CEditOptionalNotify();
enum class PerformOnChangeProcessing { No, Yes };
void vSetText(const TCHAR* pText, PerformOnChangeProcessing e);
protected:
afx_msg BOOL bConsiderEnChangeAsHandled();
bool m_bChangeNotificationsEnabled;
DECLARE_MESSAGE_MAP()
};
IMPLEMENTATION
// EditOptionalNotify.cpp : implementation file
//
#include "stdafx.h"
#include <EditOptionalNotify.h>
//IMPLEMENT_DYNAMIC(CEditOptionalNotify, CEdit)
CEditOptionalNotify::CEditOptionalNotify() :
m_bChangeNotificationsEnabled(true)
{
}
CEditOptionalNotify::~CEditOptionalNotify()
{
}
BEGIN_MESSAGE_MAP(CEditOptionalNotify, CEdit)
ON_CONTROL_REFLECT_EX(EN_CHANGE, bConsiderEnChangeAsHandled)
END_MESSAGE_MAP()
BOOL CEditOptionalNotify::bConsiderEnChangeAsHandled()
{
return (m_bChangeNotificationsEnabled ? FALSE : TRUE);
}
void CEditOptionalNotify::vSetText(const TCHAR* pText, PerformOnChangeProcessing e)
{
bool bChangeNotificationsDesired = (PerformOnChangeProcessing::No == e ? false : true);
if (bChangeNotificationsDesired != m_bChangeNotificationsEnabled)
{
m_bChangeNotificationsEnabled = bChangeNotificationsDesired;
CEdit::SetWindowText(pText);
m_bChangeNotificationsEnabled = (bChangeNotificationsDesired ? false : true);
}
else
CEdit::SetWindowText(pText);
}
I finally found a suitable solution to my problem.
First, I added a flag to my derived control's header file and I initialized it to false in the constructor
bool m_bNoEnChange;
I overrode the OnChildNotify in my derived control's header file and in the implementation, I checked for the WM_COMMAND message with the EN_CHANGE parameter. I then returned TRUE to prevent the message from being sent to the parent(dialog/page)
virtual BOOL OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult);
BOOL CADEdit::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult)
{
if(message == WM_COMMAND && HIWORD(wParam) == EN_CHANGE)
{
//If the flag is set, don't send the message to the parent window
if(m_bNoEnChange)
return TRUE;
}
return CEdit::OnChildNotify(message, wParam, lParam, pLResult);
}
Finally, when the control gains and loses focus, I wrapped the problematic SetWindowText with my flag
m_bNoEnChange = true;
SetWindowText(_T(""));
m_bNoEnChange = false;
This solution is the best in my case because I don't have to modify each dialog.