Пример #1
0
        /// <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);
        }
Пример #2
0
        /// <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();
            }
        }
Пример #3
0
        //



        /// <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;
            }
        }