/// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.Dispose"]/*' /> /// <devdoc> /// Disposes of the component. Call dispose when the component is no longer needed. /// This method removes the component from its container (if the component has a site) /// and triggers the dispose event. /// </devdoc> protected override void Dispose(bool disposing) { if (disposing) { // Remove any event sinks we have hooked up to imageLists if (imageListSmall != null) { imageListSmall.Disposed -= new EventHandler(this.DetachImageList); imageListSmall = null; } if (imageListLarge != null) { imageListLarge.Disposed -= new EventHandler(this.DetachImageList); imageListLarge = null; } if (imageListState != null) { imageListState.Disposed -= new EventHandler(this.DetachImageList); imageListState = null; } // Remove any ColumnHeaders contained in this control if (columnHeaders != null) { for (int colIdx = columnHeaders.Length-1; colIdx >= 0; colIdx--) { columnHeaders[colIdx].OwnerListview = null; columnHeaders[colIdx].Dispose(); } columnHeaders = null; } // Remove any items we have Items.Clear(); if (odCacheFontHandleWrapper != null) { odCacheFontHandleWrapper.Dispose(); odCacheFontHandleWrapper = null; } if (!String.IsNullOrEmpty(this.backgroundImageFileName) || this.bkImgFileNames != null) { // we need the fileIoPermission when the app runs on an UNC share and // the list view creates/deletes temporary files for its background image // SECREVIEW : Safe to assert FileIO here since we are deleting files created by us. // FileIOPermission fiop = new FileIOPermission(PermissionState.Unrestricted); fiop.Assert(); try { System.IO.FileInfo fi; if (!String.IsNullOrEmpty(this.backgroundImageFileName)) { fi = new System.IO.FileInfo(this.backgroundImageFileName); Debug.Assert(fi.Exists, "who deleted our temp file?"); // [....]: vsWhidbey 417804. // ComCtl ListView uses COM objects to manipulate the bitmap we send it to them. // I could not find any resources which explain in detail when the IImgCtx objects // release the temporary file. So if we get a FileIO when we delete the temporary file // we don't do anything about it ( because we don't know what is a good time to try to delete the file again ). try { fi.Delete(); } catch (System.IO.IOException){} this.backgroundImageFileName = String.Empty; } for (int i = 0; i <= this.bkImgFileNamesCount; i++) { fi = new System.IO.FileInfo(this.bkImgFileNames[i]); Debug.Assert(fi.Exists, "who deleted our temp file?"); // [....]: vsWhidbey 417804. // ComCtl ListView uses COM objects to manipulate the bitmap we send it to them. // I could not find any resources which explain in detail when the IImgCtx objects // release the temporary file. So if we get a FileIO when we delete the temporary file // we don't do anything about it ( because we don't know what is a good time to try to delete the file again ). try { fi.Delete(); } catch (System.IO.IOException){} } this.bkImgFileNames = null; this.bkImgFileNamesCount = -1; } finally { System.Security.PermissionSet.RevertAssert(); } } } base.Dispose(disposing); }
/// <include file='doc\DateTimePicker.uex' path='docs/doc[@for="DateTimePicker.OnFontChanged"]/*' /> /// <internalonly/> /// <devdoc> /// Occurs when a property for the control changes. /// </devdoc> protected override void OnFontChanged(EventArgs e) { base.OnFontChanged(e); //clear the pref height cache prefHeightCache = -1; Height = PreferredHeight; if (calendarFont == null) { calendarFontHandleWrapper = null; SetControlCalendarFont(); } }
// /// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.CustomDraw"]/*' /> /// <devdoc> /// Handles custom drawing of list items - for individual item font/color changes. /// /// If OwnerDraw is true, we fire the OnDrawItem and OnDrawSubItem (in Details view) /// events and let the user do the drawing. /// </devdoc> /// <internalonly/> unsafe void CustomDraw(ref Message m) { bool dontmess = false; bool itemDrawDefault = false; try { NativeMethods.NMLVCUSTOMDRAW* nmcd = (NativeMethods.NMLVCUSTOMDRAW*)m.LParam; // Find out which stage we're drawing switch (nmcd->nmcd.dwDrawStage) { case NativeMethods.CDDS_PREPAINT: if (OwnerDraw) { m.Result = (IntPtr)(NativeMethods.CDRF_NOTIFYITEMDRAW); return; } // We want custom draw for this paint cycle m.Result = (IntPtr)(NativeMethods.CDRF_NOTIFYSUBITEMDRAW | NativeMethods.CDRF_NEWFONT); // refresh the cache of the current color & font settings for this paint cycle odCacheBackColor = this.BackColor; odCacheForeColor = this.ForeColor; odCacheFont = this.Font; odCacheFontHandle = this.FontHandle; // If preparing to paint a group item, make sure its bolded. if (nmcd->dwItemType == NativeMethods.LVCDI_GROUP) { if (odCacheFontHandleWrapper != null) { odCacheFontHandleWrapper.Dispose(); } odCacheFont = new Font(odCacheFont, FontStyle.Bold); odCacheFontHandleWrapper = new Control.FontHandleWrapper(odCacheFont); odCacheFontHandle = odCacheFontHandleWrapper.Handle; SafeNativeMethods.SelectObject(new HandleRef(nmcd->nmcd, nmcd->nmcd.hdc), new HandleRef(odCacheFontHandleWrapper, odCacheFontHandleWrapper.Handle)); m.Result = (IntPtr)NativeMethods.CDRF_NEWFONT; } return; //We have to return a NOTIFYSUBITEMDRAW (called NOTIFYSUBITEMREDRAW in the docs) here to //get it to enter "change all subitems instead of whole rows" mode. //HOWEVER... we only want to do this for report styles... case NativeMethods.CDDS_ITEMPREPAINT: int itemIndex = (int)nmcd->nmcd.dwItemSpec; //VSWhidbey #163674 - the following call silently returns Rectangle.Empty if no corresponding // item was found. We do this because the native listview, under some circumstances, seems // to send spurious custom draw notifications. The check below does the rest. Rectangle itemBounds = GetItemRectOrEmpty(itemIndex); if (!ClientRectangle.IntersectsWith(itemBounds)) { // we don't need to bother painting this one. return; } // If OwnerDraw is true, fire the onDrawItem event. if (OwnerDraw) { Graphics g = Graphics.FromHdcInternal(nmcd->nmcd.hdc); #if DEBUGGING Rectangle r = itemBounds; Rectangle r2 = Rectangle.FromLTRB(nmcd->nmcd.rc.left, nmcd->nmcd.rc.top, nmcd->nmcd.rc.right, nmcd->nmcd.rc.bottom); Debug.WriteLine("ClipBounds : l {0} t {1} r {2} b {3}", g.ClipBounds.Left, g.ClipBounds.Top, g.ClipBounds.Right, g.ClipBounds.Bottom); Debug.WriteLine("Rect (Send Msg) : l {0} t {1} r {2} b {3}", r.Left, r.Top, r.Right, r.Bottom); Debug.WriteLine("Rect (NM) : l {0} t {1} r {2} b {3}", r2.Left, r2.Top, r2.Right, r2.Bottom); #endif DrawListViewItemEventArgs e = null; try { e = new DrawListViewItemEventArgs(g, Items[(int)nmcd->nmcd.dwItemSpec], itemBounds, (int)nmcd->nmcd.dwItemSpec, (ListViewItemStates)(nmcd->nmcd.uItemState)); OnDrawItem(e); } finally { g.Dispose(); } itemDrawDefault = e.DrawDefault; // For the Details view, we send a SKIPDEFAULT when we get a sub-item drawing notification. // For other view styles, we do it here. if (viewStyle == View.Details) { m.Result = (IntPtr)(NativeMethods.CDRF_NOTIFYSUBITEMDRAW); } else { if (!e.DrawDefault) { m.Result = (IntPtr)(NativeMethods.CDRF_SKIPDEFAULT); } } if (!e.DrawDefault) { return; // skip our regular drawing code } } if (viewStyle == View.Details || viewStyle == View.Tile) { m.Result = (IntPtr)(NativeMethods.CDRF_NOTIFYSUBITEMDRAW | NativeMethods.CDRF_NEWFONT); dontmess = true; // don't mess with our return value! //ITEMPREPAINT is used to work out the rect for the first column!!! GAH!!! //(which means we can't just do our color/font work on SUBITEM|ITEM_PREPAINT) //so fall through... and tell the end of SUBITEM|ITEM_PREPAINT not to mess //with our return value... } //If it's not a report, we fall through and change the main item's styles goto case (NativeMethods.CDDS_SUBITEM | NativeMethods.CDDS_ITEMPREPAINT); case (NativeMethods.CDDS_SUBITEM | NativeMethods.CDDS_ITEMPREPAINT): itemIndex = (int)nmcd->nmcd.dwItemSpec; //VSWhidbey #163674 - the following call silently returns Rectangle.Empty if no corresponding // item was found. We do this because the native listview, under some circumstances, seems // to send spurious custom draw notifications. The check below does the rest. itemBounds = GetItemRectOrEmpty(itemIndex); if (!ClientRectangle.IntersectsWith(itemBounds)) { // we don't need to bother painting this one. return; } // If OwnerDraw is true, fire the onDrawSubItem event. if (OwnerDraw && !itemDrawDefault) { Graphics g = Graphics.FromHdcInternal(nmcd->nmcd.hdc); DrawListViewSubItemEventArgs e = null; // by default, we want to skip the customDrawCode bool skipCustomDrawCode = true; try { //The ListView will send notifications for every column, even if no //corresponding subitem exists for a particular item. We shouldn't //fire events in such cases. if (nmcd->iSubItem < Items[itemIndex].SubItems.Count) { Rectangle subItemBounds = GetSubItemRect(itemIndex, nmcd->iSubItem); // For the first sub-item, the rectangle corresponds to the whole item. // We need to handle this case separately. if (nmcd->iSubItem == 0 && Items[itemIndex].SubItems.Count > 1) { // Use the width for the first column header. subItemBounds.Width = this.columnHeaders[0].Width; } if (this.ClientRectangle.IntersectsWith(subItemBounds)) { e = new DrawListViewSubItemEventArgs(g, subItemBounds, Items[itemIndex], Items[itemIndex].SubItems[nmcd->iSubItem], itemIndex, nmcd->iSubItem, columnHeaders[nmcd->iSubItem], (ListViewItemStates)(nmcd->nmcd.uItemState)); OnDrawSubItem(e); // the customer still wants to draw the default. // Don't skip the custom draw code then skipCustomDrawCode = !e.DrawDefault; } } } finally { g.Dispose(); } if (skipCustomDrawCode) { m.Result = (IntPtr)(NativeMethods.CDRF_SKIPDEFAULT); return; // skip our custom draw code } } // get the node ListViewItem item = Items[(int)(nmcd->nmcd.dwItemSpec)]; // if we're doing the whole row in one style, change our result! if (dontmess && item.UseItemStyleForSubItems) { m.Result = (IntPtr)NativeMethods.CDRF_NEWFONT; } Debug.Assert(item != null, "Item was null in ITEMPREPAINT"); int state = nmcd->nmcd.uItemState; // There is a known and documented problem in the ListView winctl control - // if the LVS_SHOWSELALWAYS style is set, then the item state will have // the CDIS_SELECTED bit set for all items. So we need to verify with the // real item state to be sure. if (!HideSelection) { int realState = GetItemState((int)(nmcd->nmcd.dwItemSpec)); if ((realState & NativeMethods.LVIS_SELECTED) == 0) { state &= ~NativeMethods.CDIS_SELECTED; } } // subitem is invalid if the flag isn't set -- and we also use this code in // cases where subitems aren't visible (ie. non-Details modes), so if subitem // is invalid, point it at the main item's render info int subitem = ((nmcd->nmcd.dwDrawStage & NativeMethods.CDDS_SUBITEM) != 0) ? nmcd->iSubItem : 0; // Work out the style in which to render this item // Font subItemFont = null; Color subItemForeColor = Color.Empty; Color subItemBackColor = Color.Empty; bool haveRenderInfo = false; bool disposeSubItemFont = false; if (item != null && subitem < item.SubItems.Count) { haveRenderInfo = true; if (subitem == 0 && (state & NativeMethods.CDIS_HOT) != 0 && HotTracking) { disposeSubItemFont = true; subItemFont = new Font(item.SubItems[0].Font, FontStyle.Underline); } else { subItemFont = item.SubItems[subitem].Font; } if (subitem > 0 || (state & (NativeMethods.CDIS_SELECTED | NativeMethods.CDIS_GRAYED | NativeMethods.CDIS_HOT | NativeMethods.CDIS_DISABLED)) == 0) { // we only propogate colors if we're displaying things normally // the user can override this method to do all kinds of other crazy things if they // want to though - but we don't support that. subItemForeColor = item.SubItems[subitem].ForeColor; subItemBackColor = item.SubItems[subitem].BackColor; } } // We always have to set font and color data, because of comctl design // Color riFore = Color.Empty; Color riBack = Color.Empty; if (haveRenderInfo) { riFore = subItemForeColor; riBack = subItemBackColor; } bool changeColor = true; if (!Enabled) { changeColor = false; } else if ((activation == ItemActivation.OneClick) || (activation == ItemActivation.TwoClick)) { if ((state & (NativeMethods.CDIS_SELECTED | NativeMethods.CDIS_GRAYED | NativeMethods.CDIS_HOT | NativeMethods.CDIS_DISABLED)) != 0) { changeColor = false; } } if (changeColor) { if (!haveRenderInfo || riFore.IsEmpty) { nmcd->clrText = ColorTranslator.ToWin32(odCacheForeColor); } else { nmcd->clrText = ColorTranslator.ToWin32(riFore); } // Work-around for a comctl quirk where, // if clrText is the same as SystemColors.HotTrack, // the subitem's color is not changed to nmcd->clrText. // // Try to tweak the blue component of clrText first, then green, then red. // Basically, if the color component is 0xFF, subtract 1 from it // (adding 1 will overflow), else add 1 to it. If the color component is 0, // skip it and go to the next color (unless it is our last option). if (nmcd->clrText == ColorTranslator.ToWin32(SystemColors.HotTrack)) { int totalshift = 0; bool clrAdjusted = false; int mask = 0xFF0000; do { int C = nmcd->clrText & mask; if (C != 0 || (mask == 0x0000FF)) // The color is not 0 // or this is the last option { int n = 16 - totalshift; // Make sure the value doesn't overflow if (C == mask) { C = ((C >> n) - 1) << n; } else { C = ((C >> n) + 1) << n; } // Copy the adjustment into nmcd->clrText nmcd->clrText = (nmcd->clrText & (~mask)) | C; clrAdjusted = true; } else { mask >>= 8; // Try the next color. // We try adjusting Blue, Green, Red in that order, // since 0x0000FF is the most likely value of // SystemColors.HotTrack totalshift += 8; } } while (!clrAdjusted); } if (!haveRenderInfo || riBack.IsEmpty) { nmcd->clrTextBk = ColorTranslator.ToWin32(odCacheBackColor); } else { nmcd->clrTextBk = ColorTranslator.ToWin32(riBack); } } if (!haveRenderInfo || subItemFont == null) { // safety net code just in case if (odCacheFont != null) { SafeNativeMethods.SelectObject(new HandleRef(nmcd->nmcd, nmcd->nmcd.hdc), new HandleRef(null, odCacheFontHandle)); } } else { if (odCacheFontHandleWrapper != null) { odCacheFontHandleWrapper.Dispose(); } odCacheFontHandleWrapper = new Control.FontHandleWrapper(subItemFont); SafeNativeMethods.SelectObject(new HandleRef(nmcd->nmcd, nmcd->nmcd.hdc), new HandleRef(odCacheFontHandleWrapper, odCacheFontHandleWrapper.Handle)); } if (!dontmess) { m.Result = (IntPtr)NativeMethods.CDRF_NEWFONT; } if (disposeSubItemFont) { subItemFont.Dispose(); } return; default: m.Result = (IntPtr)NativeMethods.CDRF_DODEFAULT; return; } } catch (Exception e) { Debug.Fail("Exception occurred attempting to setup custom draw. Disabling custom draw for this control", e.ToString()); m.Result = (IntPtr)NativeMethods.CDRF_DODEFAULT; } }