Iterating over ListView Items win32 api - c++

I currently have a handle to my Listview via HWND lv = GetDlgItem(hDlg, MY_LISTVIEW)
and its currently populated with items using ListView_SetItemText();
I want to update each item in that listview based on data that has been updated externally. How would I iterate over each listview item given my handle?

ListViews use a 0-based index to identify items, so to iterate over the items it's simply a matter of getting the total and then running a loop that counts from 0. For example,
int iNumItems = ListView_GetItemCount(lv);
for (int iIndex = 0; iIndex < iNumItems; ++iIndex)
{
// update this item
ListView_SetItemText(lv, iIndex, 0, ...);
}

Related

Unsorting a sorted TreeView list in win32/winapi

this is the sorting code. When the user toggles the sort button this runs and sorts the TreeView
void TreeView::sort(HTREEITEM hTreeItem, bool isRecusive)
{
::SendMessage(_hSelf, TVM_SORTCHILDREN, TRUE, reinterpret_cast<LPARAM>(hTreeItem));
if (!isRecusive)
return;
for (HTREEITEM hItem = getChildFrom(hTreeItem); hItem != NULL; hItem = getNextSibling(hItem))
sort(hItem, isRecusive);
}
win32 already provides a TVM_SORTCHILDREN message to sort a TreeView. I want to unsort the treeview list to the previous state, when the user toggles the sort button from an on state to an off state.
One way to solve this; is to store the treestate before sorting the treeview. Can someone guide me on how to implement this?

issue with retrieving current list item text from CListCtrl

I am trying to retrieve the selected list item from CListCtrl. The first item text is retrieved correct. Later on when I go select next, only the previous list item text is retrieved. Below is my event method that is triggered when I select an item from CListCtrl.
example scenario
List(m_RListCtrl) -> Item1, Item2, Item3
First time I click/select Item2. Item2 text displayed in m_EditBox.
Next I click Item3. Item2 is still displayed
Then I click Item1. Item3 is displayed in the editbox
then I click Item2. Item1 is displayed.
...
...
...
event code :
void CRTConfigDlg::OnLvnItemchangedRepoConfigList(NMHDR *pNMHDR, LRESULT *pResult)
{
CString itemText = L"";
itemText = m_RListCtrl.GetItemText(m_RListCtrl.GetSelectionMark(), 0);
m_EditBox.SetWindowText(itemText);
//UpdateWindow();
}
I have even tried following solution from Get Index of Item Text in MFC CListCtrl. But still the issue was same.
Can you help me to know , where I am going wrong?
You can also use the Itemchanged Notification but you have to keep in mind, that this event is triggered when an item is selected and deselected.
So you need to examin the items state.
void CAnyDialogClass::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
// check if the items state changed to selected.
if ((pNMLV->uChanged & LVIF_STATE)!=0 &&
(pNMLV->uOldState & LVIS_SELECTED)==0 &&
(pNMLV->uNewState & LVIS_SELECTED)!=0)
{
// This item is selected now
...
Even more precise is to use LVIS_FOCUSED. The user may change the focus of an item by just holding the Ctrl key and using the cursor movement keys.
You need to iterate through selected items like this:
int nColumns = m_RListCtrl.GetHeaderCtrl()->GetItemCount();
POSITION pos = m_RListCtrl.GetFirstSelectedItemPosition();
while (pos)
{
int nItem = m_RListCtrl.GetNextSelectedItem(pos);
for(int i=0; i<nColumns; i++)
{
CString sItem = m_RListCtrl.GetItemText(nItem, i);
// TO DO: do stuff with item text here
}
}

Sitecore workbox only display the latest Version of an item

I have customized workbox by overriding it. By default Workbox displays all versions of items in a particular workflow state.
I need only the last version to appear in the workbox.
Played around with the DisplayStates(IWorkflow workflow, XmlControl placeholder) method, but no luck.
How can I do this?
You need to override DisplayStates() method and filter the DataUri[] items array:
List<DataUri> filteredUriList = new List<DataUri>();
DataUri[] items = this.GetItems(state, workflow);
for (int index = offset; index < num; ++index)
{
Item obj = Sitecore.Context.ContentDatabase.Items[items[index]];
if (obj != null && obj.Versions.IsLatestVersion())
filteredUriList.Add(items[index]);
}
items = filteredUriList.ToArray();

Sitecore workbox change sort order

By default Sitecore workbox displays the Item name, and sort the item list by Item name.
In one of my previous posts regarding this I managed to change the item name to a custom field.
Now I need to sort workbox by this field. How can I do this?
Assuming that you already have your own implementation of the WorkboxForm as described in the post you linked in your question, you need to change the code of the DisplayState method.
The DataUri[] items inflow parameter of this method gives you the list of all items which are in given state of the workflows. You need to retrieve all the Sitecore items from this parameter and sort them:
DataUri[] items = new DataUri[0];
List<Item> sitecoreItems = items
.Select(uri => Context.ContentDatabase.Items[uri])
.OrderBy(item => item["YourCustomField"])
.ToList();
And use the new list for selecting the current page items. This solution is not optimized for the performance - you need to get every item in given state from database so you can access the custom field.
After studying Sitecore workbox modifications, I came across with following solution.
Step 1 - Modify the GetItems method as follows,
private DataUri[] GetItems(WorkflowState state, IWorkflow workflow)
{
if (workflow != null)
{
var items = workflow.GetItems(state.StateID);
Array.Sort(items, new Comparison<DataUri>(CompareDataUri));
return items;
}
return new DataUri[] { };
}
Here comes the "CompareDataUri" method,
private int CompareDataUri(DataUri x, DataUri y)
{
//Custom method written to compare two values - Dhanuka
Item itemX = Sitecore.Context.ContentDatabase.GetItem(x);
Item itemY = Sitecore.Context.ContentDatabase.GetItem(y);
string m_sortField = "__Updated";
bool m_descSort = false;
var res = 0;
res = string.Compare(itemX[m_sortField], itemY[m_sortField]);
if (m_descSort)
{
if (res > 0)
return -1;
if (res < 0)
return 1;
}
return res;
}
This approach is optimized for performance.

MFC ListView Change Item Image

I have added items to ListControl, they have images. Now I want to change them, I tried to do GetItem and SetItem, but I was not able. At least I don't know how to get an Item I want. How I can change Image of an item in ListView?
Thanks
P.S.
I've managed to solve it. Here is solution:
This is how to loop
LVITEMW pitem;
ZeroMemory(&pitem, sizeof(pitem));
pitem.mask = LVIF_TEXT | LVIF_IMAGE;
pitem.iItem = <SET INDEX OF YOUR ITEMS HERE, YOU CAN LOOP HERE>;
pitem.iSubItem = 0;
pitem.pszText = new wchar_t[256];
pitem.cchTextMax = 255;
mlist.GetItem(&pitem);
And after selecting an item, you can change it's image like this:
pitem.iImage = newindex;
mlist.SetItem(&pitem);
Using CListCtrl::SetItem is right. You have to set the nMask parameter to LVIF_IMAGE and provide the index of the image in der image-list in the iImage parameter.
The solution highlighted in the first post was not working for me. After a short look to Microsoft Documentation, the signature of the SetItem function is:
BOOL SetItem(const LVITEM* pItem);
pItem should be a pointer to a LVITEM which is const, which is not really the case in this situation...
However, the next solution is working for me:
// Let's say my CListCtrl is named m_listCtrl
// Loop on items of CListCtrl
for( int i = 0; i < m_listCtrl.GetItemCount(); i++ )
{
// And then you define a new image with the index iImage for the item i
m_listCtrl.SetItem(i, 0, LVIF_IMAGE, NULL,
iImage, 0, 0, 0);
}