Implement TitleImageIndex/Key to ListViewGroup (#3490)

This commit is contained in:
Loni Tra 2020-06-26 03:39:49 -07:00 коммит произвёл GitHub
Родитель 3d6c0bb497
Коммит d4fca96a43
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
22 изменённых файлов: 1041 добавлений и 113 удалений

Просмотреть файл

@ -0,0 +1,6 @@
System.Windows.Forms.ListViewGroup.TitleImageIndex.get -> int
System.Windows.Forms.ListViewGroup.TitleImageIndex.set -> void
System.Windows.Forms.ListViewGroup.TitleImageKey.get -> string!
System.Windows.Forms.ListViewGroup.TitleImageKey.set -> void
~System.Windows.Forms.ListView.GroupImageList.get -> System.Windows.Forms.ImageList
~System.Windows.Forms.ListView.GroupImageList.set -> void

Просмотреть файл

@ -6710,4 +6710,7 @@ Stack trace where the illegal operation occurred was:
<data name="InputLanguageCultureNotFound" xml:space="preserve">
<value>Could not find an InputLanguage for culture '{0}'.</value>
</data>
<data name="ListViewGroupImageListDescr" xml:space="preserve">
<value>The ImageList control used by the ListView for ListViewGroup images in all views.</value>
</data>
</root>

5
src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf сгенерированный
Просмотреть файл

@ -6376,6 +6376,11 @@ Trasování zásobníku, kde došlo k neplatné operaci:
<target state="translated">ListViewGroup</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupImageListDescr">
<source>The ImageList control used by the ListView for ListViewGroup images in all views.</source>
<target state="new">The ImageList control used by the ListView for ListViewGroup images in all views.</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupNameDescr">
<source>The name of this group.</source>
<target state="translated">Název této skupiny</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf сгенерированный
Просмотреть файл

@ -6376,6 +6376,11 @@ Stapelüberwachung, in der der unzulässige Vorgang auftrat:
<target state="translated">ListViewGroup</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupImageListDescr">
<source>The ImageList control used by the ListView for ListViewGroup images in all views.</source>
<target state="new">The ImageList control used by the ListView for ListViewGroup images in all views.</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupNameDescr">
<source>The name of this group.</source>
<target state="translated">Der Name dieser Gruppe.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf сгенерированный
Просмотреть файл

@ -6376,6 +6376,11 @@ El seguimiento de la pila donde tuvo lugar la operación no válida fue:
<target state="translated">ListViewGroup</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupImageListDescr">
<source>The ImageList control used by the ListView for ListViewGroup images in all views.</source>
<target state="new">The ImageList control used by the ListView for ListViewGroup images in all views.</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupNameDescr">
<source>The name of this group.</source>
<target state="translated">Nombre de este grupo.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf сгенерированный
Просмотреть файл

@ -6376,6 +6376,11 @@ Cette opération non conforme s'est produite sur la trace de la pile :
<target state="translated">ListViewGroup</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupImageListDescr">
<source>The ImageList control used by the ListView for ListViewGroup images in all views.</source>
<target state="new">The ImageList control used by the ListView for ListViewGroup images in all views.</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupNameDescr">
<source>The name of this group.</source>
<target state="translated">Nom de ce groupe.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf сгенерированный
Просмотреть файл

@ -6376,6 +6376,11 @@ Traccia dello stack da cui si è verificata l'operazione non valida:
<target state="translated">ListViewGroup</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupImageListDescr">
<source>The ImageList control used by the ListView for ListViewGroup images in all views.</source>
<target state="new">The ImageList control used by the ListView for ListViewGroup images in all views.</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupNameDescr">
<source>The name of this group.</source>
<target state="translated">Il nome del gruppo.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf сгенерированный
Просмотреть файл

@ -6376,6 +6376,11 @@ Stack trace where the illegal operation occurred was:
<target state="translated">ListViewGroup</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupImageListDescr">
<source>The ImageList control used by the ListView for ListViewGroup images in all views.</source>
<target state="new">The ImageList control used by the ListView for ListViewGroup images in all views.</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupNameDescr">
<source>The name of this group.</source>
<target state="translated">このグループの名前です。</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf сгенерированный
Просмотреть файл

@ -6376,6 +6376,11 @@ Stack trace where the illegal operation occurred was:
<target state="translated">ListViewGroup</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupImageListDescr">
<source>The ImageList control used by the ListView for ListViewGroup images in all views.</source>
<target state="new">The ImageList control used by the ListView for ListViewGroup images in all views.</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupNameDescr">
<source>The name of this group.</source>
<target state="translated">이 그룹의 이름입니다.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf сгенерированный
Просмотреть файл

@ -6376,6 +6376,11 @@ Stos śledzenia, w którym wystąpiła zabroniona operacja:
<target state="translated">ListViewGroup</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupImageListDescr">
<source>The ImageList control used by the ListView for ListViewGroup images in all views.</source>
<target state="new">The ImageList control used by the ListView for ListViewGroup images in all views.</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupNameDescr">
<source>The name of this group.</source>
<target state="translated">Nazwa tej grupy.</target>

Просмотреть файл

@ -6376,6 +6376,11 @@ Rastreamento de pilha em que a operação ilegal ocorreu:
<target state="translated">ListViewGroup</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupImageListDescr">
<source>The ImageList control used by the ListView for ListViewGroup images in all views.</source>
<target state="new">The ImageList control used by the ListView for ListViewGroup images in all views.</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupNameDescr">
<source>The name of this group.</source>
<target state="translated">O nome deste grupo.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf сгенерированный
Просмотреть файл

@ -6377,6 +6377,11 @@ Stack trace where the illegal operation occurred was:
<target state="translated">ListViewGroup</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupImageListDescr">
<source>The ImageList control used by the ListView for ListViewGroup images in all views.</source>
<target state="new">The ImageList control used by the ListView for ListViewGroup images in all views.</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupNameDescr">
<source>The name of this group.</source>
<target state="translated">Имя данной группы.</target>

5
src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf сгенерированный
Просмотреть файл

@ -6376,6 +6376,11 @@ Geçersiz işlemin gerçekleştiği yığın izi:
<target state="translated">ListViewGroup</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupImageListDescr">
<source>The ImageList control used by the ListView for ListViewGroup images in all views.</source>
<target state="new">The ImageList control used by the ListView for ListViewGroup images in all views.</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupNameDescr">
<source>The name of this group.</source>
<target state="translated">Bu grubun adı.</target>

Просмотреть файл

@ -6376,6 +6376,11 @@ Stack trace where the illegal operation occurred was:
<target state="translated">ListViewGroup</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupImageListDescr">
<source>The ImageList control used by the ListView for ListViewGroup images in all views.</source>
<target state="new">The ImageList control used by the ListView for ListViewGroup images in all views.</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupNameDescr">
<source>The name of this group.</source>
<target state="translated">此组的名称。</target>

Просмотреть файл

@ -6376,6 +6376,11 @@ Stack trace where the illegal operation occurred was:
<target state="translated">ListViewGroup</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupImageListDescr">
<source>The ImageList control used by the ListView for ListViewGroup images in all views.</source>
<target state="new">The ImageList control used by the ListView for ListViewGroup images in all views.</target>
<note />
</trans-unit>
<trans-unit id="ListViewGroupNameDescr">
<source>The name of this group.</source>
<target state="translated">此群組的名稱。</target>

Просмотреть файл

@ -110,9 +110,10 @@ namespace System.Windows.Forms
private IntPtr odCacheFontHandle = IntPtr.Zero;
private FontHandleWrapper odCacheFontHandleWrapper = null;
private ImageList imageListLarge;
private ImageList imageListSmall;
private ImageList imageListState;
private ImageList _imageListLarge;
private ImageList _imageListSmall;
private ImageList _imageListState;
private ImageList _imageListGroup;
private MouseButtons downButton;
private int itemCount;
@ -574,11 +575,11 @@ namespace System.Windows.Forms
// Setting the LVS_CHECKBOXES window style also causes the ListView to display the default checkbox
// images rather than the user specified StateImageList. We send a LVM_SETIMAGELIST to restore the
// user's images.
if (IsHandleCreated && imageListState != null)
if (IsHandleCreated && _imageListState != null)
{
if (CheckBoxes)
{ // we want custom checkboxes
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.STATE, imageListState.Handle);
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.STATE, _imageListState.Handle);
}
else
{
@ -925,6 +926,51 @@ namespace System.Windows.Forms
}
}
/// <summary>
/// The currently set GroupIcon image list.
/// </summary>
/// <value>
/// An <see cref="ImageList"/> that contains the icons to use for <see cref="ListViewGroup"/>.
/// The default is <see langword="null"/>.
/// </value>
/// <remarks>
/// <para>
/// The <see cref="GroupImageList"/> property allows you to specify an <see cref="ImageList"/> object that
/// contains icons to use when displaying groups. The <see cref="ListView"/> control can accept any graphics
/// format that the <see cref="ImageList"/> control supports when displaying icons. The <see cref="ListView"/>
/// control is not limited to .ico files. Once an <see cref="ImageList"/> is assigned to the <see cref="GroupImageList"/>
/// property, you can set the <see cref="ListViewGroup.TitleImageIndex"/> property of each <see cref="ListViewGroup"/>
/// in the <see cref="ListView"/> control to the index position of the appropriate image in the <see cref="ImageList"/>.
/// The size of the icons for the <see cref="GroupImageList"/> is specified by the <see cref="ImageList.ImageSize"/> property.
/// </para>
/// </remarks>
[SRCategory(nameof(SR.CatBehavior))]
[DefaultValue(null)]
[SRDescription(nameof(SR.ListViewGroupImageListDescr))]
public ImageList GroupImageList
{
get => _imageListGroup;
set
{
if (_imageListGroup == value)
{
return;
}
DetachGroupImageListHandlers();
_imageListGroup = value;
AttachGroupImageListHandlers();
if (!IsHandleCreated)
{
return;
}
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.GROUPHEADER,
value is null ? IntPtr.Zero : value.Handle);
}
}
/// <summary>
/// The collection of groups belonging to this ListView
/// </summary>
@ -1172,16 +1218,16 @@ namespace System.Windows.Forms
[SRDescription(nameof(SR.ListViewLargeImageListDescr))]
public ImageList LargeImageList
{
get => imageListLarge;
get => _imageListLarge;
set
{
if (value == imageListLarge)
if (value == _imageListLarge)
{
return;
}
DetachLargeImageListHandlers();
imageListLarge = value;
_imageListLarge = value;
AttachLargeImageListHandlers();
if (!IsHandleCreated)
@ -1411,16 +1457,16 @@ namespace System.Windows.Forms
[SRDescription(nameof(SR.ListViewSmallImageListDescr))]
public ImageList SmallImageList
{
get => imageListSmall;
get => _imageListSmall;
set
{
if (imageListSmall == value)
if (_imageListSmall == value)
{
return;
}
DetachSmallImageListListHandlers();
imageListSmall = value;
_imageListSmall = value;
AttachSmallImageListListHandlers();
if (!IsHandleCreated)
@ -1520,10 +1566,10 @@ namespace System.Windows.Forms
[SRDescription(nameof(SR.ListViewStateImageListDescr))]
public ImageList StateImageList
{
get => imageListState;
get => _imageListState;
set
{
if (imageListState == value)
if (_imageListState == value)
{
return;
}
@ -1531,7 +1577,7 @@ namespace System.Windows.Forms
if (UseCompatibleStateImageBehavior)
{
DetachStateImageListHandlers();
imageListState = value;
_imageListState = value;
AttachStateImageListHandlers();
if (IsHandleCreated)
@ -1543,7 +1589,7 @@ namespace System.Windows.Forms
{
DetachStateImageListHandlers();
if (IsHandleCreated && imageListState != null && CheckBoxes)
if (IsHandleCreated && _imageListState != null && CheckBoxes)
{
// If CheckBoxes are set to true, then we will have to recreate the handle.
// For some reason, if CheckBoxes are set to true and the list view has a state imageList, then the native listView destroys
@ -1554,7 +1600,7 @@ namespace System.Windows.Forms
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.STATE, IntPtr.Zero);
}
imageListState = value;
_imageListState = value;
AttachStateImageListHandlers();
if (!IsHandleCreated)
@ -1569,7 +1615,8 @@ namespace System.Windows.Forms
}
else
{
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.STATE, (imageListState is null || imageListState.Images.Count == 0) ? IntPtr.Zero : imageListState.Handle);
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.STATE,
(_imageListState is null || _imageListState.Images.Count == 0) ? IntPtr.Zero : _imageListState.Handle);
}
// Comctl should handle auto-arrange for us, but doesn't
@ -2204,41 +2251,54 @@ namespace System.Windows.Forms
/// </summary>
public void ArrangeIcons() => ArrangeIcons((ListViewAlignment)LVA.DEFAULT);
private void AttachGroupImageListHandlers()
{
if (_imageListGroup is null)
{
return;
}
// NOTE: any handlers added here should be removed in DetachGroupImageListHandlers
_imageListGroup.RecreateHandle += new EventHandler(GroupImageListRecreateHandle);
_imageListGroup.Disposed += new EventHandler(DetachImageList);
_imageListGroup.ChangeHandle += new EventHandler(GroupImageListChangedHandle);
}
private void AttachLargeImageListHandlers()
{
if (imageListLarge is null)
if (_imageListLarge is null)
{
return;
}
// NOTE: any handlers added here should be removed in DetachLargeImageListHandlers
imageListLarge.RecreateHandle += new EventHandler(LargeImageListRecreateHandle);
imageListLarge.Disposed += new EventHandler(DetachImageList);
imageListLarge.ChangeHandle += new EventHandler(LargeImageListChangedHandle);
_imageListLarge.RecreateHandle += new EventHandler(LargeImageListRecreateHandle);
_imageListLarge.Disposed += new EventHandler(DetachImageList);
_imageListLarge.ChangeHandle += new EventHandler(LargeImageListChangedHandle);
}
private void AttachSmallImageListListHandlers()
{
if (imageListSmall is null)
if (_imageListSmall is null)
{
return;
}
// NOTE: any handlers added here should be removed in DetachSmallImageListListHandlers
imageListSmall.RecreateHandle += new EventHandler(SmallImageListRecreateHandle);
imageListSmall.Disposed += new EventHandler(DetachImageList);
_imageListSmall.RecreateHandle += new EventHandler(SmallImageListRecreateHandle);
_imageListSmall.Disposed += new EventHandler(DetachImageList);
}
private void AttachStateImageListHandlers()
{
if (imageListState is null)
if (_imageListState is null)
{
return;
}
// NOTE: any handlers added here should be removed in DetachStateImageListHandlers
imageListState.RecreateHandle += new EventHandler(StateImageListRecreateHandle);
imageListState.Disposed += new EventHandler(DetachImageList);
_imageListState.RecreateHandle += new EventHandler(StateImageListRecreateHandle);
_imageListState.Disposed += new EventHandler(DetachImageList);
}
public void AutoResizeColumns(ColumnHeaderAutoResizeStyle headerAutoResize)
@ -2888,25 +2948,30 @@ namespace System.Windows.Forms
try
{
#if DEBUG
if (sender != imageListSmall && sender != imageListState && sender != imageListLarge)
if (sender != _imageListSmall && sender != _imageListState && sender != _imageListLarge && sender != _imageListGroup)
{
Debug.Fail("ListView sunk dispose event from unknown component");
}
#endif // DEBUG
if (sender == imageListSmall)
if (sender == _imageListSmall)
{
SmallImageList = null;
}
if (sender == imageListLarge)
if (sender == _imageListLarge)
{
LargeImageList = null;
}
if (sender == imageListState)
if (sender == _imageListState)
{
StateImageList = null;
}
if (sender == _imageListGroup)
{
GroupImageList = null;
}
}
finally
{
@ -2916,38 +2981,50 @@ namespace System.Windows.Forms
UpdateListViewItemsLocations();
}
private void DetachLargeImageListHandlers()
private void DetachGroupImageListHandlers()
{
if (imageListLarge is null)
if (_imageListGroup is null)
{
return;
}
imageListLarge.RecreateHandle -= new EventHandler(LargeImageListRecreateHandle);
imageListLarge.Disposed -= new EventHandler(DetachImageList);
imageListLarge.ChangeHandle -= new EventHandler(LargeImageListChangedHandle);
_imageListGroup.RecreateHandle -= new EventHandler(GroupImageListRecreateHandle);
_imageListGroup.Disposed -= new EventHandler(DetachImageList);
_imageListGroup.ChangeHandle -= new EventHandler(GroupImageListChangedHandle);
}
private void DetachLargeImageListHandlers()
{
if (_imageListLarge is null)
{
return;
}
_imageListLarge.RecreateHandle -= new EventHandler(LargeImageListRecreateHandle);
_imageListLarge.Disposed -= new EventHandler(DetachImageList);
_imageListLarge.ChangeHandle -= new EventHandler(LargeImageListChangedHandle);
}
private void DetachSmallImageListListHandlers()
{
if (imageListSmall is null)
if (_imageListSmall is null)
{
return;
}
imageListSmall.RecreateHandle -= new EventHandler(SmallImageListRecreateHandle);
imageListSmall.Disposed -= new EventHandler(DetachImageList);
_imageListSmall.RecreateHandle -= new EventHandler(SmallImageListRecreateHandle);
_imageListSmall.Disposed -= new EventHandler(DetachImageList);
}
private void DetachStateImageListHandlers()
{
if (imageListState is null)
if (_imageListState is null)
{
return;
}
imageListState.RecreateHandle -= new EventHandler(StateImageListRecreateHandle);
imageListState.Disposed -= new EventHandler(DetachImageList);
_imageListState.RecreateHandle -= new EventHandler(StateImageListRecreateHandle);
_imageListState.Disposed -= new EventHandler(DetachImageList);
}
/// <summary>
@ -2961,11 +3038,13 @@ namespace System.Windows.Forms
{
// Remove any event sinks we have hooked up to imageLists
DetachSmallImageListListHandlers();
imageListSmall = null;
_imageListSmall = null;
DetachLargeImageListHandlers();
imageListLarge = null;
_imageListLarge = null;
DetachStateImageListHandlers();
imageListState = null;
_imageListState = null;
DetachGroupImageListHandlers();
_imageListGroup = null;
// Remove any ColumnHeaders contained in this control
if (columnHeaders != null)
@ -3582,6 +3661,32 @@ namespace System.Windows.Forms
return result;
}
private void GroupImageListChangedHandle(object sender, EventArgs e)
{
if (VirtualMode || sender is null || sender != _imageListGroup || !IsHandleCreated)
{
return;
}
foreach (ListViewGroup group in Groups)
{
group.TitleImageIndex = group.ImageIndexer.ActualIndex < _imageListGroup.Images.Count
? group.ImageIndexer.ActualIndex
: _imageListGroup.Images.Count - 1;
}
}
private void GroupImageListRecreateHandle(object sender, EventArgs e)
{
if (!IsHandleCreated)
{
return;
}
IntPtr handle = (GroupImageList is null) ? IntPtr.Zero : GroupImageList.Handle;
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.GROUPHEADER, handle);
}
public ListViewHitTestInfo HitTest(Point point)
{
return HitTest(point.X, point.Y);
@ -4144,32 +4249,30 @@ namespace System.Windows.Forms
private void LargeImageListRecreateHandle(object sender, EventArgs e)
{
if (IsHandleCreated)
if (!IsHandleCreated)
{
IntPtr handle = (LargeImageList == null) ? IntPtr.Zero : LargeImageList.Handle;
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.NORMAL, handle);
ForceCheckBoxUpdate();
return;
}
IntPtr handle = (LargeImageList is null) ? IntPtr.Zero : LargeImageList.Handle;
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.NORMAL, handle);
ForceCheckBoxUpdate();
}
private void LargeImageListChangedHandle(object sender, EventArgs e)
{
if (VirtualMode || sender is null || sender != imageListLarge || !IsHandleCreated)
if (VirtualMode || sender is null || sender != _imageListLarge || !IsHandleCreated)
{
return;
}
foreach (ListViewItem item in Items)
{
if (item.ImageIndexer.ActualIndex != ImageList.Indexer.DefaultIndex && item.ImageIndexer.ActualIndex >= imageListLarge.Images.Count)
{
SetItemImage(item.Index, imageListLarge.Images.Count - 1);
}
else
{
SetItemImage(item.Index, item.ImageIndexer.ActualIndex);
}
int imageIndex = item.ImageIndexer.ActualIndex < _imageListLarge.Images.Count
? item.ImageIndexer.ActualIndex
: _imageListLarge.Images.Count - 1;
SetItemImage(item.Index, imageIndex);
}
}
@ -4728,19 +4831,24 @@ namespace System.Windows.Forms
User32.SendMessageW(this, (User32.WM)LVM.SETTEXTCOLOR, IntPtr.Zero, PARAM.FromColor(c));
}
if (null != imageListLarge)
if (_imageListLarge != null)
{
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.NORMAL, imageListLarge.Handle);
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.NORMAL, _imageListLarge.Handle);
}
if (null != imageListSmall)
if (_imageListSmall != null)
{
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.SMALL, imageListSmall.Handle);
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.SMALL, _imageListSmall.Handle);
}
if (null != imageListState)
if (_imageListState != null)
{
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.STATE, imageListState.Handle);
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.STATE, _imageListState.Handle);
}
if (_imageListGroup != null)
{
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.GROUPHEADER, _imageListGroup.Handle);
}
}
@ -5124,11 +5232,11 @@ namespace System.Windows.Forms
User32.DestroyWindow(oldHandle);
}
internal void SetItemImage(int index, int image)
internal void SetItemImage(int itemIndex, int imageIndex)
{
if (index < 0 || (VirtualMode && index >= VirtualListSize) || (!VirtualMode && index >= itemCount))
if (itemIndex < 0 || (VirtualMode && itemIndex >= VirtualListSize) || (!VirtualMode && itemIndex >= itemCount))
{
throw new ArgumentOutOfRangeException(nameof(index), index, string.Format(SR.InvalidArgument, nameof(index), index));
throw new ArgumentOutOfRangeException(nameof(itemIndex), itemIndex, string.Format(SR.InvalidArgument, nameof(itemIndex), itemIndex));
}
if (!IsHandleCreated)
@ -5139,8 +5247,8 @@ namespace System.Windows.Forms
var lvItem = new LVITEMW
{
mask = LVIF.IMAGE,
iItem = index,
iImage = image
iItem = itemIndex,
iImage = imageIndex
};
User32.SendMessageW(this, (User32.WM)LVM.SETITEMW, IntPtr.Zero, ref lvItem);
}
@ -5262,13 +5370,15 @@ namespace System.Windows.Forms
private void SmallImageListRecreateHandle(object sender, EventArgs e)
{
if (IsHandleCreated)
if (!IsHandleCreated)
{
IntPtr handle = (SmallImageList == null) ? IntPtr.Zero : SmallImageList.Handle;
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.SMALL, handle);
ForceCheckBoxUpdate();
return;
}
IntPtr handle = (SmallImageList is null) ? IntPtr.Zero : SmallImageList.Handle;
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.SMALL, handle);
ForceCheckBoxUpdate();
}
/// <summary>
@ -5292,15 +5402,13 @@ namespace System.Windows.Forms
private void StateImageListRecreateHandle(object sender, EventArgs e)
{
if (IsHandleCreated)
if (!IsHandleCreated)
{
IntPtr handle = IntPtr.Zero;
if (imageListState != null)
{
handle = imageListState.Handle;
}
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.STATE, handle);
return;
}
IntPtr handle = (StateImageList is null) ? IntPtr.Zero : StateImageList.Handle;
User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.STATE, handle);
}
/// <summary>
@ -5444,8 +5552,9 @@ namespace System.Windows.Forms
var lvgroup = new LVGROUPW
{
cbSize = (uint)sizeof(LVGROUPW),
mask = LVGF.HEADER | LVGF.FOOTER | LVGF.ALIGN | LVGF.STATE | LVGF.SUBTITLE | LVGF.TASK | additionalMask,
mask = LVGF.HEADER | LVGF.FOOTER | LVGF.ALIGN | LVGF.STATE | LVGF.SUBTITLE | LVGF.TASK | LVGF.TITLEIMAGE | additionalMask,
cchHeader = header.Length,
iTitleImage = -1,
iGroupId = group.ID
};
@ -5471,6 +5580,11 @@ namespace System.Windows.Forms
break;
}
if (group.TitleImageIndex != ImageList.Indexer.DefaultIndex || group.TitleImageKey != ImageList.Indexer.DefaultKey)
{
lvgroup.iTitleImage = group.ImageIndexer.ActualIndex;
}
fixed (char* pSubtitle = subtitle)
fixed (char* pTask = task)
fixed (char* pHeader = header)
@ -5622,7 +5736,7 @@ namespace System.Windows.Forms
if (CheckBoxes)
{
ListViewHitTestInfo lvhti = HitTest(x, y);
if (imageListState != null && imageListState.Images.Count < 2)
if (_imageListState != null && _imageListState.Images.Count < 2)
{
// When the user clicks on the check box and the listView's state image list
// does not have 2 images, comctl will give us an AttemptToDivideByZero exception.

Просмотреть файл

@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
@ -34,6 +33,8 @@ namespace System.Windows.Forms
private static int s_nextHeader = 1;
private ListViewGroupImageIndexer? _imageIndexer;
/// <summary>
/// Creates a ListViewGroup.
/// </summary>
@ -175,7 +176,8 @@ namespace System.Windows.Forms
/// Controls which <see cref="ListViewGroupCollapsedState"/> the group will appear as.
/// </summary>
/// <value>
/// One of the <see cref="ListViewGroupCollapsedState"/> values that specifies how the group is displayed. The default is <see cref="ListViewGroupCollapsedState.Default"/>.
/// One of the <see cref="ListViewGroupCollapsedState"/> values that specifies how the group is displayed.
/// The default is <see cref="ListViewGroupCollapsedState.Default"/>.
/// </value>
/// <exception cref="InvalidEnumArgumentException">
/// The specified value when setting this property is not a valid <see cref="ListViewGroupCollapsedState"/> value.
@ -242,6 +244,79 @@ namespace System.Windows.Forms
}
}
/// <summary>
/// Gets or sets the index of the image that is displayed for the group.
/// </summary>
/// <value>
/// The zero-based index of the image in the ImageList that is displayed for the group. The default is -1.
/// </value>
/// <exception cref="ArgumentOutOfRangeException">
/// The value specified is less than -1.
/// </exception>
[DefaultValue(-1)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(Drawing.Design.UITypeEditor))]
[Localizable(true)]
[RefreshProperties(RefreshProperties.Repaint)]
[SRCategory(nameof(SR.CatBehavior))]
[TypeConverter(typeof(NoneExcludedImageIndexConverter))]
public int TitleImageIndex
{
get
{
ImageList? imageList = ImageIndexer.ImageList;
return imageList == null || ImageIndexer.Index < imageList.Images.Count
? ImageIndexer.Index
: imageList.Images.Count - 1;
}
set
{
if (value < ImageList.Indexer.DefaultIndex)
{
throw new ArgumentOutOfRangeException(nameof(value), value,
string.Format(SR.InvalidLowBoundArgumentEx, nameof(TitleImageIndex), value, ImageList.Indexer.DefaultIndex));
}
if (ImageIndexer.Index == value && value != ImageList.Indexer.DefaultIndex)
{
return;
}
ImageIndexer.Index = value;
UpdateListView();
}
}
/// <summary>
/// Gets or sets the key of the image that is displayed for the group.
/// </summary>
/// <value>
/// The key for the image that is displayed for the group.
/// </value>
[DefaultValue("")]
[TypeConverter(typeof(ImageKeyConverter))]
[Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(Drawing.Design.UITypeEditor))]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[RefreshProperties(RefreshProperties.Repaint)]
[SRCategory(nameof(SR.CatBehavior))]
[Localizable(true)]
public string TitleImageKey
{
get => ImageIndexer.Key;
set
{
if (ImageIndexer.Key == value && value != ImageList.Indexer.DefaultKey)
{
return;
}
ImageIndexer.Key = value;
UpdateListView();
}
}
internal ListViewGroupImageIndexer ImageIndexer => _imageIndexer ??= new ListViewGroupImageIndexer(this);
internal int ID { get; }
/// <summary>

Просмотреть файл

@ -0,0 +1,37 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
namespace System.Windows.Forms
{
/// <summary>
/// We need a special way to defer to the ListView's image list for indexing purposes.
/// ListViewGroupImageIndexer is a class used to support <see cref="ListViewGroup.TitleImageIndex"/> and
/// <see cref="ListViewGroup.TitleImageKey"/>.
/// </summary>
internal class ListViewGroupImageIndexer : ImageList.Indexer
{
private readonly ListViewGroup _owner;
/// <summary>
/// Initializes a new instance of the <see cref="ListViewGroupImageIndexer"/> class.
/// </summary>
/// <param name="group">The <see cref="ListViewGroup"/> that this object belongs to.</param>
public ListViewGroupImageIndexer(ListViewGroup group)
{
_owner = group;
}
/// <summary>
/// Gets the <see cref="ListView.GroupImageList"/> of the <see cref="ListView"/>
/// associated with the group.
/// </summary>
public override ImageList? ImageList
{
get => _owner.ListView?.GroupImageList;
set => Debug.Fail("We should never set the image list");
}
}
}

Просмотреть файл

@ -58,24 +58,6 @@ namespace System.Windows.Forms
private string toolTipText = string.Empty;
private object userData;
// We need a special way to defer to the ListView's image
// list for indexing purposes.
internal class ListViewItemImageIndexer : ImageList.Indexer
{
private readonly ListViewItem _owner;
public ListViewItemImageIndexer(ListViewItem item)
{
_owner = item;
}
public override ImageList ImageList
{
get => _owner?.ImageList;
set => Debug.Fail("We should never set the image list");
}
}
public ListViewItem()
{
StateSelected = false;
@ -443,30 +425,28 @@ namespace System.Windows.Forms
{
get
{
if (ImageIndexer.Index != ImageList.Indexer.DefaultIndex && ImageList != null && ImageIndexer.Index >= ImageList.Images.Count)
{
return ImageList.Images.Count - 1;
}
return ImageIndexer.Index;
return ImageList == null || ImageIndexer.Index < ImageList.Images.Count
? ImageIndexer.Index
: ImageList.Images.Count - 1;
}
set
{
if (value < ImageList.Indexer.DefaultIndex)
{
throw new ArgumentOutOfRangeException(nameof(value), value, string.Format(SR.InvalidLowBoundArgumentEx, nameof(ImageIndex), value, ImageList.Indexer.DefaultIndex));
throw new ArgumentOutOfRangeException(nameof(value), value,
string.Format(SR.InvalidLowBoundArgumentEx, nameof(ImageIndex), value, ImageList.Indexer.DefaultIndex));
}
ImageIndexer.Index = value;
if (listView != null && listView.IsHandleCreated)
{
listView.SetItemImage(Index, ImageIndexer.ActualIndex);
listView.SetItemImage(itemIndex: Index, imageIndex: ImageIndexer.ActualIndex);
}
}
}
internal ListViewItemImageIndexer ImageIndexer => imageIndexer ?? (imageIndexer = new ListViewItemImageIndexer(this));
internal ListViewItemImageIndexer ImageIndexer => imageIndexer ??= new ListViewItemImageIndexer(this);
/// <summary>
/// Returns the ListViewItem's currently set image index

Просмотреть файл

@ -0,0 +1,36 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
namespace System.Windows.Forms
{
/// <summary>
/// We need a special way to defer to the ListView's image list for indexing purposes.
/// ListViewItemImageIndexer is a class used to support <see cref="ListViewItem.ImageIndex"/> and
/// <see cref="ListViewItem.ImageKey"/>.
/// </summary>
internal class ListViewItemImageIndexer : ImageList.Indexer
{
private readonly ListViewItem _owner;
/// <summary>
/// Initializes a new instance of the <see cref="ListViewItemImageIndexer"/> class.
/// </summary>
/// <param name="item">The <see cref="ListViewItem"/> that this object belongs to.</param>
public ListViewItemImageIndexer(ListViewItem item)
{
_owner = item;
}
/// <summary>
/// Gets the <see cref="ListViewItem.ImageList"/> associated with the item.
/// </summary>
public override ImageList? ImageList
{
get => _owner.ImageList;
set => Debug.Fail("We should never set the image list");
}
}
}

Просмотреть файл

@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
@ -36,6 +37,8 @@ namespace System.Windows.Forms.Tests
Assert.Null(group.Tag);
Assert.Equal(ListViewGroupCollapsedState.Default, group.CollapsedState);
Assert.Empty(group.TaskLink);
Assert.Empty(group.TitleImageKey);
Assert.Equal(-1, group.TitleImageIndex);
}
[WinFormsTheory]
@ -55,6 +58,8 @@ namespace System.Windows.Forms.Tests
Assert.Null(group.Tag);
Assert.Equal(ListViewGroupCollapsedState.Default, group.CollapsedState);
Assert.Empty(group.TaskLink);
Assert.Empty(group.TitleImageKey);
Assert.Equal(-1, group.TitleImageIndex);
}
public static IEnumerable<object[]> Ctor_String_HorizontalAlignment_TestData()
@ -83,6 +88,8 @@ namespace System.Windows.Forms.Tests
Assert.Null(group.Tag);
Assert.Equal(ListViewGroupCollapsedState.Default, group.CollapsedState);
Assert.Empty(group.TaskLink);
Assert.Empty(group.TitleImageKey);
Assert.Equal(-1, group.TitleImageIndex);
}
public static IEnumerable<object[]> Ctor_String_String_TestData()
@ -109,6 +116,278 @@ namespace System.Windows.Forms.Tests
Assert.Null(group.Tag);
Assert.Equal(ListViewGroupCollapsedState.Default, group.CollapsedState);
Assert.Empty(group.TaskLink);
Assert.Empty(group.TitleImageKey);
Assert.Equal(-1, group.TitleImageIndex);
}
[WinFormsTheory]
[CommonMemberData(nameof(CommonTestHelper.GetNonNegativeIntTheoryData))]
[InlineData(-1)]
public void ListViewGroup_TitleImageIndex_SetWithoutListView_GetReturnsExpected(int value)
{
var group = new ListViewGroup
{
TitleImageIndex = value
};
Assert.Equal(value, group.TitleImageIndex);
// Set same.
group.TitleImageIndex = value;
Assert.Equal(value, group.TitleImageIndex);
}
[WinFormsTheory]
[CommonMemberData(nameof(CommonTestHelper.GetNonNegativeIntTheoryData))]
[InlineData(-1)]
public void ListViewGroup_TitleImageIndex_SetWithListView_GetReturnsExpected(int value)
{
using var listView = new ListView();
var group = new ListViewGroup();
listView.Groups.Add(group);
group.TitleImageIndex = value;
Assert.Equal(value, group.TitleImageIndex);
Assert.False(listView.IsHandleCreated);
// Set same.
group.TitleImageIndex = value;
Assert.Equal(value, group.TitleImageIndex);
Assert.False(listView.IsHandleCreated);
}
[WinFormsTheory]
[CommonMemberData(nameof(CommonTestHelper.GetNonNegativeIntTheoryData))]
[InlineData(-1)]
public void ListViewGroup_TitleImageIndex_SetWithListViewWithHandle_GetReturnsExpected(int value)
{
using var listView = new ListView();
var group = new ListViewGroup();
listView.Groups.Add(group);
Assert.NotEqual(IntPtr.Zero, listView.Handle);
int invalidatedCallCount = 0;
listView.Invalidated += (sender, e) => invalidatedCallCount++;
int styleChangedCallCount = 0;
listView.StyleChanged += (sender, e) => styleChangedCallCount++;
int createdCallCount = 0;
listView.HandleCreated += (sender, e) => createdCallCount++;
group.TitleImageIndex = value;
Assert.Equal(value, group.TitleImageIndex);
Assert.True(listView.IsHandleCreated);
Assert.Equal(0, invalidatedCallCount);
Assert.Equal(0, styleChangedCallCount);
Assert.Equal(0, createdCallCount);
// Set same.
group.TitleImageIndex = value;
Assert.Equal(value, group.TitleImageIndex);
Assert.True(listView.IsHandleCreated);
Assert.Equal(0, invalidatedCallCount);
Assert.Equal(0, styleChangedCallCount);
Assert.Equal(0, createdCallCount);
}
// Need to verify test once RE fixed.
[WinFormsFact(Skip = "Crash with AbandonedMutexException. See: https://github.com/dotnet/arcade/issues/5325")]
public unsafe void ListViewGroup_TitleImageIndex_GetGroupInfo_Success()
{
// Run this from another thread as we call Application.EnableVisualStyles.
using RemoteInvokeHandle invokerHandle = RemoteExecutor.Invoke(() =>
{
var data = new (int, int)[] { (-1, -1), (0 , 0), (1, 1), (2, -1) };
foreach ((int Index, int Expected) value in data)
{
Application.EnableVisualStyles();
using var listView = new ListView();
using var groupImageList = new ImageList();
groupImageList.Images.Add(new Bitmap(10, 10));
groupImageList.Images.Add(new Bitmap(20, 20));
listView.GroupImageList = groupImageList;
Assert.Equal(groupImageList.Handle,
User32.SendMessageW(listView.Handle, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.GROUPHEADER, groupImageList.Handle));
var group = new ListViewGroup();
listView.Groups.Add(group);
Assert.NotEqual(IntPtr.Zero, listView.Handle);
group.TitleImageIndex = value.Index;
Assert.Equal((IntPtr)1, User32.SendMessageW(listView.Handle, (User32.WM)LVM.GETGROUPCOUNT, IntPtr.Zero, IntPtr.Zero));
var lvgroup = new LVGROUPW
{
cbSize = (uint)sizeof(LVGROUPW),
mask = LVGF.TITLEIMAGE | LVGF.GROUPID,
};
Assert.Equal((IntPtr)1, User32.SendMessageW(listView.Handle, (User32.WM)LVM.GETGROUPINFOBYINDEX, (IntPtr)0, ref lvgroup));
Assert.Equal(value.Expected, lvgroup.iTitleImage);
Assert.True(lvgroup.iGroupId >= 0);
}
});
// verify the remote process succeeded
Assert.Equal(0, invokerHandle.ExitCode);
}
[WinFormsFact]
public void ListViewGroup_TitleImageIndex_SetInvalid_ThrowsArgumentOutOfRangeException()
{
var random = new Random();
int value = random.Next(2, int.MaxValue) * -1;
var group = new ListViewGroup();
Assert.Throws<ArgumentOutOfRangeException>("value", () => group.TitleImageIndex = value);
}
[WinFormsTheory]
[CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))]
public void ListViewGroup_TitleImageIndex_SetTitleImageKey_GetReturnsExpected(string key, string expected)
{
var group = new ListViewGroup
{
TitleImageIndex = 0
};
Assert.Equal(0, group.TitleImageIndex);
// verify TitleImageIndex resets to default once TitleImageKey is set
group.TitleImageKey = key;
Assert.Equal(expected, group.TitleImageKey);
Assert.Equal(ImageList.Indexer.DefaultIndex, group.TitleImageIndex);
}
[WinFormsTheory]
[CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))]
[InlineData("te\0xt", "te\0xt")]
public void ListViewGroup_TitleImageKey_SetWithoutListView_GetReturnsExpected(string value, string expected)
{
var group = new ListViewGroup
{
TitleImageKey = value
};
Assert.Equal(expected, group.TitleImageKey);
// Set same.
group.TitleImageKey = value;
Assert.Equal(expected, group.TitleImageKey);
}
[WinFormsTheory]
[CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))]
[InlineData("te\0xt", "te\0xt")]
public void ListViewGroup_TitleImageKey_SetWithListView_GetReturnsExpected(string value, string expected)
{
using var listView = new ListView();
var group = new ListViewGroup();
listView.Groups.Add(group);
group.TitleImageKey = value;
Assert.Equal(expected, group.TitleImageKey);
Assert.False(listView.IsHandleCreated);
// Set same.
group.TitleImageKey = value;
Assert.Equal(expected, group.TitleImageKey);
Assert.False(listView.IsHandleCreated);
}
[WinFormsTheory]
[InlineData(null, "")]
[InlineData("", "")]
[InlineData("header", "header")]
[InlineData("te\0xt", "te\0xt")]
[InlineData("ListViewGroup", "ListViewGroup")]
public void ListViewGroup_TitleImageKey_SetWithListViewWithHandle_GetReturnsExpected(string value, string expected)
{
using var listView = new ListView();
var group = new ListViewGroup();
listView.Groups.Add(group);
Assert.NotEqual(IntPtr.Zero, listView.Handle);
int invalidatedCallCount = 0;
listView.Invalidated += (sender, e) => invalidatedCallCount++;
int styleChangedCallCount = 0;
listView.StyleChanged += (sender, e) => styleChangedCallCount++;
int createdCallCount = 0;
listView.HandleCreated += (sender, e) => createdCallCount++;
group.TitleImageKey = value;
Assert.Equal(expected, group.TitleImageKey);
Assert.True(listView.IsHandleCreated);
Assert.Equal(0, invalidatedCallCount);
Assert.Equal(0, styleChangedCallCount);
Assert.Equal(0, createdCallCount);
// Set same.
group.TitleImageKey = value;
Assert.Equal(expected, group.TitleImageKey);
Assert.True(listView.IsHandleCreated);
Assert.Equal(0, invalidatedCallCount);
Assert.Equal(0, styleChangedCallCount);
Assert.Equal(0, createdCallCount);
}
// Need to verify test once RE fixed.
[WinFormsFact(Skip = "Crash with AbandonedMutexException. See: https://github.com/dotnet/arcade/issues/5325")]
public unsafe void ListViewGroup_TitleImageKey_GetGroupInfo_Success()
{
// Run this from another thread as we call Application.EnableVisualStyles.
using RemoteInvokeHandle invokerHandle = RemoteExecutor.Invoke(() =>
{
var data = new (string, int)[] { (null, -1), (string.Empty, -1), ("text", 0), ("te\0t", 0) };
foreach ((string Key, int ExpectedIndex) value in data)
{
Application.EnableVisualStyles();
using var listView = new ListView();
using var groupImageList = new ImageList();
groupImageList.Images.Add(value.Key, new Bitmap(10, 10));
listView.GroupImageList = groupImageList;
Assert.Equal(groupImageList.Handle,
User32.SendMessageW(listView.Handle, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.GROUPHEADER, groupImageList.Handle));
var group = new ListViewGroup();
listView.Groups.Add(group);
Assert.NotEqual(IntPtr.Zero, listView.Handle);
group.TitleImageKey = value.Key;
Assert.Equal((IntPtr)1, User32.SendMessageW(listView.Handle, (User32.WM)LVM.GETGROUPCOUNT, IntPtr.Zero, IntPtr.Zero));
var lvgroup = new LVGROUPW
{
cbSize = (uint)sizeof(LVGROUPW),
mask = LVGF.TITLEIMAGE | LVGF.GROUPID
};
Assert.Equal((IntPtr)1, User32.SendMessageW(listView.Handle, (User32.WM)LVM.GETGROUPINFOBYINDEX, (IntPtr)0, ref lvgroup));
Assert.Equal(value.ExpectedIndex, lvgroup.iTitleImage);
Assert.True(lvgroup.iGroupId >= 0);
}
});
// verify the remote process succeeded
Assert.Equal(0, invokerHandle.ExitCode);
}
[WinFormsTheory]
[CommonMemberData(nameof(CommonTestHelper.GetNonNegativeIntTheoryData))]
[InlineData(-1)]
public void ListViewGroup_TitleImageKey_SetTitleImageIndex_GetReturnsExpected(int value)
{
var group = new ListViewGroup
{
TitleImageKey = "key"
};
Assert.Equal("key", group.TitleImageKey);
// verify TitleImageKey resets to default once TitleImageIndex is set
group.TitleImageIndex = value;
Assert.Equal(value, group.TitleImageIndex);
Assert.Equal(ImageList.Indexer.DefaultKey, group.TitleImageKey);
}
[WinFormsTheory]
@ -120,6 +399,7 @@ namespace System.Windows.Forms.Tests
{
Subtitle = value
};
Assert.Equal(expected, group.Subtitle);
// Set same.
@ -218,6 +498,7 @@ namespace System.Windows.Forms.Tests
pszSubtitle = buffer,
cchSubtitle = 256
};
Assert.Equal((IntPtr)1, User32.SendMessageW(listView.Handle, (User32.WM)LVM.GETGROUPINFOBYINDEX, (IntPtr)0, ref lvgroup));
Assert.Equal(expected, new string(lvgroup.pszSubtitle));
Assert.True(lvgroup.iGroupId >= 0);
@ -237,6 +518,7 @@ namespace System.Windows.Forms.Tests
{
Footer = value
};
Assert.Equal(expected, group.Footer);
// Set same.
@ -327,6 +609,7 @@ namespace System.Windows.Forms.Tests
pszFooter = buffer,
cchFooter = 256
};
Assert.Equal((IntPtr)1, User32.SendMessageW(listView.Handle, (User32.WM)LVM.GETGROUPINFOBYINDEX, (IntPtr)0, ref lvgroup));
Assert.Equal(expected, new string(lvgroup.pszFooter));
Assert.True(lvgroup.iGroupId >= 0);
@ -357,6 +640,7 @@ namespace System.Windows.Forms.Tests
Footer = footer,
FooterAlignment = value
};
Assert.Equal(value, group.FooterAlignment);
Assert.Equal(expectedFooter, group.Footer);
@ -375,6 +659,7 @@ namespace System.Windows.Forms.Tests
{
Footer = footer
};
listView.Groups.Add(group);
group.FooterAlignment = value;
@ -398,6 +683,7 @@ namespace System.Windows.Forms.Tests
{
Footer = footer
};
listView.Groups.Add(group);
Assert.NotEqual(IntPtr.Zero, listView.Handle);
int invalidatedCallCount = 0;
@ -452,6 +738,7 @@ namespace System.Windows.Forms.Tests
{
Footer = footer
};
listView.Groups.Add(group1);
Assert.NotEqual(IntPtr.Zero, listView.Handle);
@ -466,6 +753,7 @@ namespace System.Windows.Forms.Tests
pszFooter = buffer,
cchFooter = 256
};
Assert.Equal((IntPtr)1, User32.SendMessageW(listView.Handle, (User32.WM)LVM.GETGROUPINFOBYINDEX, (IntPtr)0, ref lvgroup));
Assert.Equal(footer, new string(lvgroup.pszFooter));
Assert.True(lvgroup.iGroupId >= 0);
@ -490,6 +778,7 @@ namespace System.Windows.Forms.Tests
{
Header = value
};
Assert.Equal(expected, group.Header);
// Set same.
@ -580,6 +869,7 @@ namespace System.Windows.Forms.Tests
pszHeader = buffer,
cchHeader = 256
};
Assert.Equal((IntPtr)1, User32.SendMessageW(listView.Handle, (User32.WM)LVM.GETGROUPINFOBYINDEX, (IntPtr)0, ref lvgroup));
Assert.Equal(expected, new string(lvgroup.pszHeader));
Assert.True(lvgroup.iGroupId >= 0);
@ -600,6 +890,7 @@ namespace System.Windows.Forms.Tests
Header = header,
HeaderAlignment = value
};
Assert.Equal(value, group.HeaderAlignment);
Assert.Equal(expectedHeader, group.Header);
@ -618,6 +909,7 @@ namespace System.Windows.Forms.Tests
{
Header = header
};
listView.Groups.Add(group);
group.HeaderAlignment = value;
@ -641,6 +933,7 @@ namespace System.Windows.Forms.Tests
{
Header = header
};
listView.Groups.Add(group);
Assert.NotEqual(IntPtr.Zero, listView.Handle);
int invalidatedCallCount = 0;
@ -695,6 +988,7 @@ namespace System.Windows.Forms.Tests
{
Header = header
};
listView.Groups.Add(group1);
Assert.NotEqual(IntPtr.Zero, listView.Handle);
@ -709,6 +1003,7 @@ namespace System.Windows.Forms.Tests
pszHeader = buffer,
cchHeader = 256
};
Assert.Equal((IntPtr)1, User32.SendMessageW(listView.Handle, (User32.WM)LVM.GETGROUPINFOBYINDEX, (IntPtr)0, ref lvgroup));
Assert.Equal(header, new string(lvgroup.pszHeader));
Assert.True(lvgroup.iGroupId >= 0);
@ -868,6 +1163,7 @@ namespace System.Windows.Forms.Tests
{
Name = value
};
Assert.Same(value, group.Name);
// Set same.
@ -994,6 +1290,7 @@ namespace System.Windows.Forms.Tests
{
Tag = value
};
Assert.Same(value, group.Tag);
// Set same.

Просмотреть файл

@ -88,6 +88,7 @@ namespace System.Windows.Forms.Tests
Assert.False(control.GridLines);
Assert.Empty(control.Groups);
Assert.Same(control.Groups, control.Groups);
Assert.Null(control.GroupImageList);
Assert.False(control.HasChildren);
Assert.Equal(ColumnHeaderStyle.Clickable, control.HeaderStyle);
Assert.Equal(97, control.Height);
@ -1518,6 +1519,320 @@ namespace System.Windows.Forms.Tests
Assert.Equal(0, createdCallCount);
}
public static IEnumerable<object[]> GroupImageList_Set_GetReturnsExpected()
{
var nonEmptyImageList = new ImageList();
nonEmptyImageList.Images.Add(new Bitmap(10, 10));
foreach (bool autoArrange in new bool[] { true, false })
{
foreach (bool virtualMode in new bool[] { true, false })
{
foreach (View view in new View[] { View.Details, View.LargeIcon, View.List, View.SmallIcon })
{
yield return new object[] { autoArrange, virtualMode, view, null };
yield return new object[] { autoArrange, virtualMode, view, new ImageList() };
yield return new object[] { autoArrange, virtualMode, view, nonEmptyImageList };
}
}
yield return new object[] { autoArrange, false, View.Tile, null };
yield return new object[] { autoArrange, false, View.Tile, new ImageList() };
yield return new object[] { autoArrange, false, View.Tile, nonEmptyImageList };
}
}
[WinFormsTheory]
[MemberData(nameof(GroupImageList_Set_GetReturnsExpected))]
public void ListView_GroupImageList_Set_GetReturnsExpected(bool autoArrange, bool virtualMode, View view, ImageList value)
{
using var listView = new ListView
{
AutoArrange = autoArrange,
VirtualMode = virtualMode,
View = view,
GroupImageList = value
};
Assert.Same(value, listView.GroupImageList);
Assert.False(listView.IsHandleCreated);
// Set same.
listView.GroupImageList = value;
Assert.Same(value, listView.GroupImageList);
Assert.False(listView.IsHandleCreated);
}
[WinFormsTheory]
[MemberData(nameof(GroupImageList_Set_GetReturnsExpected))]
public void ListView_GroupImageList_SetWithNonNullOldValue_GetReturnsExpected(bool autoArrange, bool virtualMode, View view, ImageList value)
{
using var imageList = new ImageList();
using var listView = new ListView
{
AutoArrange = autoArrange,
VirtualMode = virtualMode,
View = view,
GroupImageList = imageList
};
listView.GroupImageList = value;
Assert.Same(value, listView.GroupImageList);
Assert.False(listView.IsHandleCreated);
// Set same.
listView.GroupImageList = value;
Assert.Same(value, listView.GroupImageList);
Assert.False(listView.IsHandleCreated);
}
public static IEnumerable<object[]> GroupImageList_SetWithHandle_GetReturnsExpected()
{
var nonEmptyImageList = new ImageList();
nonEmptyImageList.Images.Add(new Bitmap(10, 10));
yield return new object[] { true, false, View.Details, null };
yield return new object[] { true, false, View.Details, new ImageList() };
yield return new object[] { true, false, View.Details, nonEmptyImageList };
yield return new object[] { true, false, View.LargeIcon, null };
yield return new object[] { true, false, View.LargeIcon, new ImageList() };
yield return new object[] { true, false, View.LargeIcon, nonEmptyImageList };
yield return new object[] { true, false, View.List, null };
yield return new object[] { true, false, View.List, new ImageList() };
yield return new object[] { true, false, View.List, nonEmptyImageList };
yield return new object[] { true, false, View.SmallIcon, null };
yield return new object[] { true, false, View.SmallIcon, new ImageList() };
yield return new object[] { true, false, View.SmallIcon, nonEmptyImageList };
yield return new object[] { true, false, View.Tile, null };
yield return new object[] { true, false, View.Tile, new ImageList() };
yield return new object[] { true, false, View.Tile, nonEmptyImageList };
foreach (bool autoArrange in new bool[] { true, false })
{
yield return new object[] { autoArrange, true, View.Details, null };
yield return new object[] { autoArrange, true, View.Details, new ImageList() };
yield return new object[] { autoArrange, true, View.Details, nonEmptyImageList };
yield return new object[] { autoArrange, true, View.LargeIcon, null };
yield return new object[] { autoArrange, true, View.LargeIcon, new ImageList() };
yield return new object[] { autoArrange, true, View.LargeIcon, nonEmptyImageList };
yield return new object[] { autoArrange, true, View.List, null };
yield return new object[] { autoArrange, true, View.List, new ImageList() };
yield return new object[] { autoArrange, true, View.List, nonEmptyImageList };
yield return new object[] { autoArrange, true, View.SmallIcon, null };
yield return new object[] { autoArrange, true, View.SmallIcon, new ImageList() };
yield return new object[] { autoArrange, true, View.SmallIcon, nonEmptyImageList };
}
yield return new object[] { false, false, View.Details, null };
yield return new object[] { false, false, View.Details, new ImageList() };
yield return new object[] { false, false, View.Details, nonEmptyImageList };
yield return new object[] { false, false, View.LargeIcon, null };
yield return new object[] { false, false, View.LargeIcon, new ImageList() };
yield return new object[] { false, false, View.LargeIcon, nonEmptyImageList };
yield return new object[] { false, false, View.List, null };
yield return new object[] { false, false, View.List, new ImageList() };
yield return new object[] { false, false, View.List, nonEmptyImageList };
yield return new object[] { false, false, View.SmallIcon, null };
yield return new object[] { false, false, View.SmallIcon, new ImageList() };
yield return new object[] { false, false, View.SmallIcon, nonEmptyImageList };
yield return new object[] { false, false, View.Tile, null };
yield return new object[] { false, false, View.Tile, new ImageList() };
yield return new object[] { false, false, View.Tile, nonEmptyImageList };
}
[WinFormsTheory]
[MemberData(nameof(GroupImageList_SetWithHandle_GetReturnsExpected))]
public void ListView_GroupImageList_SetWithHandle_GetReturnsExpected(bool autoArrange, bool virtualMode, View view, ImageList value)
{
using var listView = new ListView
{
AutoArrange = autoArrange,
VirtualMode = virtualMode,
View = view
};
Assert.NotEqual(IntPtr.Zero, listView.Handle);
int invalidatedCallCount = 0;
listView.Invalidated += (sender, e) => invalidatedCallCount++;
int styleChangedCallCount = 0;
listView.StyleChanged += (sender, e) => styleChangedCallCount++;
int createdCallCount = 0;
listView.HandleCreated += (sender, e) => createdCallCount++;
listView.GroupImageList = value;
Assert.Same(value, listView.GroupImageList);
Assert.True(listView.IsHandleCreated);
Assert.Equal(0, invalidatedCallCount);
Assert.Equal(0, styleChangedCallCount);
Assert.Equal(0, createdCallCount);
// Set same.
listView.GroupImageList = value;
Assert.Same(value, listView.GroupImageList);
Assert.True(listView.IsHandleCreated);
Assert.Equal(0, invalidatedCallCount);
Assert.Equal(0, styleChangedCallCount);
Assert.Equal(0, createdCallCount);
}
public static IEnumerable<object[]> GroupImageList_SetWithHandleWithNonNullOldValue_GetReturnsExpected()
{
var nonEmptyImageList = new ImageList();
nonEmptyImageList.Images.Add(new Bitmap(10, 10));
yield return new object[] { true, false, View.Details, null };
yield return new object[] { true, false, View.Details, new ImageList() };
yield return new object[] { true, false, View.Details, nonEmptyImageList };
yield return new object[] { true, false, View.LargeIcon, null };
yield return new object[] { true, false, View.LargeIcon, new ImageList() };
yield return new object[] { true, false, View.LargeIcon, nonEmptyImageList };
yield return new object[] { true, false, View.List, null };
yield return new object[] { true, false, View.List, new ImageList() };
yield return new object[] { true, false, View.List, nonEmptyImageList };
yield return new object[] { true, false, View.SmallIcon, null };
yield return new object[] { true, false, View.SmallIcon, new ImageList() };
yield return new object[] { true, false, View.SmallIcon, nonEmptyImageList };
yield return new object[] { true, false, View.Tile, null };
yield return new object[] { true, false, View.Tile, new ImageList() };
yield return new object[] { true, false, View.Tile, nonEmptyImageList };
foreach (bool autoArrange in new bool[] { true, false })
{
yield return new object[] { autoArrange, true, View.Details, null };
yield return new object[] { autoArrange, true, View.Details, new ImageList() };
yield return new object[] { autoArrange, true, View.Details, nonEmptyImageList };
yield return new object[] { autoArrange, true, View.LargeIcon, null };
yield return new object[] { autoArrange, true, View.LargeIcon, new ImageList() };
yield return new object[] { autoArrange, true, View.LargeIcon, nonEmptyImageList };
yield return new object[] { autoArrange, true, View.List, null };
yield return new object[] { autoArrange, true, View.List, new ImageList() };
yield return new object[] { autoArrange, true, View.List, nonEmptyImageList };
yield return new object[] { autoArrange, true, View.SmallIcon, null };
yield return new object[] { autoArrange, true, View.SmallIcon, new ImageList() };
yield return new object[] { autoArrange, true, View.SmallIcon, nonEmptyImageList };
}
yield return new object[] { false, false, View.Details, null };
yield return new object[] { false, false, View.Details, new ImageList() };
yield return new object[] { false, false, View.Details, nonEmptyImageList };
yield return new object[] { false, false, View.LargeIcon, null };
yield return new object[] { false, false, View.LargeIcon, new ImageList() };
yield return new object[] { false, false, View.LargeIcon, nonEmptyImageList };
yield return new object[] { false, false, View.List, null };
yield return new object[] { false, false, View.List, new ImageList() };
yield return new object[] { false, false, View.List, nonEmptyImageList };
yield return new object[] { false, false, View.SmallIcon, null };
yield return new object[] { false, false, View.SmallIcon, new ImageList() };
yield return new object[] { false, false, View.SmallIcon, nonEmptyImageList };
yield return new object[] { false, false, View.Tile, null };
yield return new object[] { false, false, View.Tile, new ImageList() };
yield return new object[] { false, false, View.Tile, nonEmptyImageList };
}
[WinFormsTheory]
[MemberData(nameof(GroupImageList_SetWithHandleWithNonNullOldValue_GetReturnsExpected))]
public void ListView_GroupImageList_SetWithHandleWithNonNullOldValue_GetReturnsExpected(bool autoArrange, bool virtualMode, View view, ImageList value)
{
using var listView = new ListView
{
AutoArrange = autoArrange,
VirtualMode = virtualMode,
View = view,
GroupImageList = new ImageList()
};
Assert.NotEqual(IntPtr.Zero, listView.Handle);
int invalidatedCallCount = 0;
listView.Invalidated += (sender, e) => invalidatedCallCount++;
int styleChangedCallCount = 0;
listView.StyleChanged += (sender, e) => styleChangedCallCount++;
int createdCallCount = 0;
listView.HandleCreated += (sender, e) => createdCallCount++;
listView.GroupImageList = value;
Assert.Same(value, listView.GroupImageList);
Assert.True(listView.IsHandleCreated);
Assert.Equal(0, invalidatedCallCount);
Assert.Equal(0, styleChangedCallCount);
Assert.Equal(0, createdCallCount);
// Set same.
listView.GroupImageList = value;
Assert.Same(value, listView.GroupImageList);
Assert.True(listView.IsHandleCreated);
Assert.Equal(0, invalidatedCallCount);
Assert.Equal(0, styleChangedCallCount);
Assert.Equal(0, createdCallCount);
}
[WinFormsTheory]
[CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))]
public void ListView_GroupImageList_Dispose_DetachesFromListView(bool autoArrange)
{
using var imageList1 = new ImageList();
using var imageList2 = new ImageList();
using var listView = new ListView
{
AutoArrange = autoArrange,
GroupImageList = imageList1
};
Assert.Same(imageList1, listView.GroupImageList);
imageList1.Dispose();
Assert.Null(listView.GroupImageList);
Assert.False(listView.IsHandleCreated);
// Make sure we detached the setter.
listView.GroupImageList = imageList2;
imageList1.Dispose();
Assert.Same(imageList2, listView.GroupImageList);
}
[WinFormsTheory]
[InlineData(true, 1)]
[InlineData(false, 0)]
public void ListView_GroupImageList_DisposeWithHandle_DetachesFromListView(bool autoArrange, int expectedInvalidatedCallCount)
{
using var imageList1 = new ImageList();
using var imageList2 = new ImageList();
using var listView = new ListView
{
AutoArrange = autoArrange
};
Assert.NotEqual(IntPtr.Zero, listView.Handle);
int invalidatedCallCount = 0;
listView.Invalidated += (sender, e) => invalidatedCallCount++;
int styleChangedCallCount = 0;
listView.StyleChanged += (sender, e) => styleChangedCallCount++;
int createdCallCount = 0;
listView.HandleCreated += (sender, e) => createdCallCount++;
listView.GroupImageList = imageList1;
Assert.Same(imageList1, listView.GroupImageList);
Assert.True(listView.IsHandleCreated);
Assert.Equal(0, invalidatedCallCount);
Assert.Equal(0, styleChangedCallCount);
Assert.Equal(0, createdCallCount);
imageList1.Dispose();
Assert.Null(listView.GroupImageList);
Assert.True(listView.IsHandleCreated);
Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount);
Assert.Equal(0, styleChangedCallCount);
Assert.Equal(0, createdCallCount);
// Make sure we detached the setter.
listView.GroupImageList = imageList2;
imageList1.Dispose();
Assert.Same(imageList2, listView.GroupImageList);
Assert.True(listView.IsHandleCreated);
Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount);
Assert.Equal(0, styleChangedCallCount);
Assert.Equal(0, createdCallCount);
}
[WinFormsFact]
public void ListView_Handle_GetWithBackColor_Success()
{