Для справки вот что у меня работает, но это постыдный хак.Если никто не может придумать ничего лучше, чем это, это действительно печально.
Заголовок:
#pragma once
// CListCtrlEx
class CListCtrlEx : public CListCtrl
{
DECLARE_DYNAMIC(CListCtrlEx)
public:
CListCtrlEx();
virtual ~CListCtrlEx();
bool IsSelected(int index);
BOOL SelectDropTarget(int item);
protected:
DECLARE_MESSAGE_MAP()
afx_msg void OnStateChanged(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
private:
bool m_lbDown;
bool m_rbDown;
};
Реализация:
#include "stdafx.h"
#include "ListCtrlEx.h"
// CListCtrlEx
IMPLEMENT_DYNAMIC(CListCtrlEx, CListCtrl)
CListCtrlEx::CListCtrlEx() : m_lbDown(false), m_rbDown(false)
{
}
CListCtrlEx::~CListCtrlEx()
{
}
BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
ON_WM_LBUTTONDOWN()
ON_WM_RBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_RBUTTONUP()
ON_WM_MOUSEMOVE()
ON_NOTIFY_REFLECT(LVN_ODSTATECHANGED, &CListCtrlEx::OnStateChanged)
END_MESSAGE_MAP()
// CListCtrlEx message handlers
void CListCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
{
m_lbDown = true;
CListCtrl::OnLButtonDown(nFlags, point);
}
void CListCtrlEx::OnRButtonDown(UINT nFlags, CPoint point)
{
m_rbDown = true;
CListCtrl::OnRButtonDown(nFlags, point);
}
void CListCtrlEx::OnLButtonUp(UINT nFlags, CPoint point)
{
m_lbDown = false;
CListCtrl::OnLButtonUp(nFlags, point);
}
void CListCtrlEx::OnRButtonUp(UINT nFlags, CPoint point)
{
m_rbDown = false;
CListCtrl::OnRButtonUp(nFlags, point);
}
void CListCtrlEx::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_lbDown && ((nFlags & MK_LBUTTON) == 0))
{
PostMessage(WM_LBUTTONUP,
MAKEWPARAM(LOWORD(nFlags), HIWORD(nFlags)),
MAKELPARAM(point.x, point.y));
}
if (m_rbDown && ((nFlags & MK_RBUTTON) == 0))
{
PostMessage(WM_RBUTTONUP,
MAKEWPARAM(LOWORD(nFlags), HIWORD(nFlags)),
MAKELPARAM(point.x, point.y));
}
CListCtrl::OnMouseMove(nFlags, point);
}
bool CListCtrlEx::IsSelected(int index)
{
return (GetItemState(index, LVIS_SELECTED) & LVIS_SELECTED) != 0;
}
// highlight drop targets sort of like CTreeCtrl
BOOL CListCtrlEx::SelectDropTarget(int item)
{
static int prevHighlight(-1);
if (item >= 0 && item < GetItemCount())
{
if (item != prevHighlight)
{
if (prevHighlight >= 0)
{
SetItemState(prevHighlight, 0, LVIS_DROPHILITED); // remove highlight from previous target
RedrawItems(prevHighlight, prevHighlight);
}
prevHighlight = item;
SetItemState(item, LVIS_DROPHILITED, LVIS_DROPHILITED); // highlight target
RedrawItems(item, item);
UpdateWindow();
return TRUE;
}
}
else
{
for (int i(0); i < GetItemCount(); ++i)
SetItemState(i, 0, LVIS_DROPHILITED); // un-highlight all
prevHighlight = -1;
}
return FALSE;
}
void CListCtrlEx::OnStateChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
// MSDN:
// If a list-view control has the LVS_OWNERDATA style,
// and the user selects a range of items by holding down the SHIFT key and clicking the mouse,
// LVN_ITEMCHANGED notification codes are not sent for each selected or deselected item.
// Instead, you will receive a single LVN_ODSTATECHANGED notification code,
// indicating that a range of items has changed state.
NMLVODSTATECHANGE* pStateChanged = (NMLVODSTATECHANGE*)pNMHDR;
// redraw newly selected items
if (pStateChanged->uNewState == LVIS_SELECTED)
RedrawItems(pStateChanged->iFrom, pStateChanged->iTo);
}