تجاوز DrawItem لـ ListBox - لا يتم إعادة رسم العناصر غير المحددة

StackOverflow https://stackoverflow.com/questions/3274861

سؤال

هذا هو تطبيق سطح المكتب C#.ال DrawStyle ملكية لي ListBox تم ضبطه على OwnerDrawFixed.

المشكلة: لقد قمت بتجاوز DrawItem لرسم نص بخطوط مختلفة، وهو يعمل.ولكن عندما أبدأ في تغيير حجم النموذج في وقت التشغيل، يتم رسم العنصر المحدد بشكل صحيح، ولكن لا تتم إعادة رسم بقية العناصر، مما يتسبب في ظهور النص تالفًا بالنسبة للعناصر غير المحددة.

هذا هو الكود الخاص بي:

private void listDevices_DrawItem(object sender, DrawItemEventArgs e)
{
    e.DrawBackground();

    string textDevice = ((ListBox)sender).Items[e.Index].ToString();

    e.Graphics.DrawString(textDevice,
        new Font("Ariel", 15, FontStyle.Bold), new SolidBrush(Color.Black), 
        e.Bounds, StringFormat.GenericDefault);


    // Figure out where to draw IP
    StringFormat copy = new StringFormat(
        StringFormatFlags.NoWrap |
        StringFormatFlags.MeasureTrailingSpaces
    );
    copy.SetMeasurableCharacterRanges(new CharacterRange[] {new CharacterRange(0, textDevice.Length)});

    Region[] regions = e.Graphics.MeasureCharacterRanges(
        textDevice, new Font("Ariel", 15, FontStyle.Bold), e.Bounds, copy);

    int width = (int)(regions[0].GetBounds(e.Graphics).Width);
    Rectangle rect = e.Bounds;
    rect.X += width;
    rect.Width -= width;

    // draw IP
    e.Graphics.DrawString(" 255.255.255.255",
        new Font("Courier New", 10), new SolidBrush(Color.DarkBlue),
        rect, copy);

    e.DrawFocusRectangle();
}

listDevices.Items.Add("Device001");
listDevices.Items.Add("Device002");

كما أن العنصر الذي تم رسمه بشكل صحيح (العنصر المحدد) يومض عند تغيير حجم النموذج.ليس بالأمر الكبير، ولكن إذا كان أي شخص يعرف السبب ....tnx

هل كانت مفيدة؟

المحلول

ضع الكود التالي في حدث Resize :

private void listDevices_Resize(object sender, EventArgs e) {
    listDevices.Invalidate();
}

وهذا يجب أن يتسبب في إعادة رسم كل شيء.

لإيقاف الوميض، تحتاج إلى تخزين مؤقت مزدوج.

للقيام بذلك، قم بإنشاء فئة جديدة، مشتقة من ListBox، ووضع ما يلي في المنشئ:

this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

أو فقط الصق هذا في ملف التعليمات البرمجية:

using System.Windows.Forms;

namespace Whatever {
    public class DBListBox : ListBox {
        public DBListBox(): base() {
            this.DoubleBuffered = true;
            // OR
            // this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        }
    }
}

استبدل "مهما كان" بمساحة الاسم التي يستخدمها مشروعك، أو اجعلها شيئًا أكثر فائدة.بعد التجميع، يجب أن تكون قادرًا على إضافة DBListBox في مصمم النموذج.

نصائح أخرى

أنا أعيد صياغة المشكلة.هناك العديد من الأخطاء في الكود، اسم الخط هو "Arial"، يجب عدم ضبط المستقيم. العرض، نسيت استدعاء Dispose() على الخطوط والفرش والمناطق.لكنهم لا يفسرون السلوك.هناك خطأ ما في منطقة القطع يمنع تحديث النص بشكل صحيح.لا أرى أين يحدث ذلك، فحالة كائن الرسومات على ما يرام.

Graphics.DrawString() هي طريقة مزعجة للغاية، ويجب عليك تجنبها حقًا.تستخدم كافة عناصر تحكم نماذج Windows، بما في ذلك ListBox، TextRenderer.DrawText().هذا يحل المشكلة عندما أستخدمه.أعلم أن القياس أكثر صعوبة، ويمكنك التغلب على ذلك من خلال عرض عنوان IP بإزاحة ثابتة.يبدو الأمر أفضل أيضًا، حيث سيصطفون في عمود بهذه الطريقة.

يومض لأنك تستخدم e.DrawBackground().يؤدي ذلك إلى مسح النص الموجود، ويمكنك رسم النص عليه مرة أخرى.لا أعتقد أن التخزين المؤقت المزدوج سيصلح ذلك، سيتعين عليك رسم العنصر بأكمله حتى لا تضطر إلى رسم الخلفية.قد يكون الأمر صعبًا إذا لم تتمكن من الحصول على الحجم الدقيق للنص بالخط الكبير، فالحل البديل هو الرسم في صورة نقطية أولاً.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top