سؤال

لدي عنصر تحكم مستخدم يحتوي على TableLayoutPanel مكون من عمودين ويقبل أوامر لإضافة صفوف ديناميكيًا لعرض تفاصيل العنصر المحدد في عنصر تحكم منفصل.لذلك، سيحدد المستخدم صفًا في عنصر التحكم الآخر (DataGridView)، وفي معالج الأحداث SelectedItemChanged لـ DataGridView، أقوم بمسح عنصر التحكم التفصيلي ثم إعادة إنشاء كافة الصفوف للعنصر المحدد الجديد (الذي قد يحتوي على تفاصيل مختلفة تمامًا عرض من العنصر المحدد مسبقًا).هذا يعمل بشكل رائع لفترة من الوقت.ولكن إذا واصلت الانتقال من عنصر محدد إلى آخر لفترة طويلة، تصبح عمليات التحديث بطيئة جدًا (من 3 إلى 5 ثوانٍ لكل منها).هذا يجعل الأمر يبدو وكأنني لا أتخلص من كل شيء بشكل صحيح، لكن لا أستطيع معرفة ما أفتقده.إليك الكود الخاص بي لمسح TableLayoutPanel:

private readonly List<Control> controls;

public void Clear()
{
    detailTable.Visible = false;
    detailTable.SuspendLayout();
    SuspendLayout();
    detailTable.RowStyles.Clear();
    detailTable.Controls.Clear();
    DisposeAndClearControls();
    detailTable.RowCount = 0;
    detailTable.ColumnCount = 2;
}

private void DisposeAndClearControls()
{
    foreach (Control control in controls)
    {
        control.Dispose();
    }
    controls.Clear();
}

وبمجرد الانتهاء من تحميل جميع عناصر التحكم التي أريدها في TableLayoutPanel لعرض التفاصيل التالية، إليك ما أسميه:

public void Render()
{
    detailTable.ResumeLayout(false);
    detailTable.PerformLayout();
    ResumeLayout(false);
    detailTable.Visible = true;
}

أنا لا أستخدم أي شيء سوى التسميات (ونادرًا ما يستخدم TextBox) داخل TableLayoutPanel، وأضيف التسميات ومربعات النص إلى قائمة عناصر التحكم (المشار إليها في DisposeAndClearControls()) عندما أقوم بإنشائها.لقد حاولت فقط التكرار على DetailTable.Controls والتخلص منها بهذه الطريقة، ولكن يبدو أنها فقدت نصف عناصر التحكم (التي يتم تحديدها من خلال التنقل عبرها في مصحح الأخطاء).بهذه الطريقة أعلم أنني حصلت عليهم جميعًا.

سأكون مهتمًا بأية اقتراحات لتحسين أداء الرسم، ولكن بشكل خاص ما الذي يسبب التدهور في التحديدات المتعددة.

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

المحلول 3

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

من المؤسف أن TableLayoutPanel يتسرب بهذه الطريقة.

نصائح أخرى

ما عليك سوى استخدام عنصر تحكم مخصص يرث من TableLayoutPanel وتعيين خاصية DoubleBuffered على القيمة true، ويعمل بشكل رائع...خاصة عند إضافة الصفوف أو إزالتها ديناميكيًا.

public CustomLayout()
{
   this.DoubleBuffered = true;
   InitializeComponent();
}

واجهت مشكلة مماثلة مع TableLayout.إذا استخدمت TableLayout.Controls.Clear() الطريقة، لم يتم التخلص من عناصر التحكم الفرعية مطلقًا، ولكن عندما أسقطت TableLayout ببساطة دون مسحها، توقف التسرب.في الماضي، من المضحك أنني استخدمت طريقة Clear لـ يمنع نوع من التسرب.

على ما يبدو، لا تتخلص الطريقة الواضحة من عناصر التحكم (وهذا أمر منطقي، لأن حقيقة قيامك بإزالتها من TableLayout لا تعني أنك انتهيت منها) وإزالة عناصر التحكم الفرعية من TableLayout تمنع روتين التنظيف من التخلص منها الأطفال عندما يتم التخلص من LayoutTable نفسه (ببساطة لم يعد يعرف شيئًا عنهم بعد الآن).

توصيتي:حذف DetailTable.Controls.Clear(); سطر، قم بإزالة جدول التفاصيل نفسه من الجدول الأصلي ضوابط قم بتجميعها والتخلص منها، ثم قم بإنشاء TableLayout جديد تمامًا للجولة التالية.تفقد أيضًا طريقة DisposeAndClearControls تمامًا لأنك لن تحتاج إليها.في تجربتي، عملت بشكل جيد.

بهذه الطريقة، لن تضطر إلى إعادة تدوير عنصر تحكم المستخدم بالكامل بعد الآن، ولكن فقط TableLayout الموجود بداخله.

واجهت نفس المشكلة ووجدت طريقة جيدة دون تغيير الكثير:

في VB.net

Dim tp As Type = tlpMyPanel.GetType().BaseType
Dim pi As Reflection.PropertyInfo = _
    tp.GetProperty("DoubleBuffered", _ 
    Reflection.BindingFlags.Instance _
    Or Reflection.BindingFlags.NonPublic)
pi.SetValue(tlpMyPanel, True, Nothing)

أو في C#:

Type tp = tlpMyPanel.GetType().BaseType;
System.Reflection.PropertyInfo pi = 
    tp.GetProperty("DoubleBuffered",
    System.Reflection.BindingFlags.Instance 
    | System.Reflection.BindingFlags.NonPublic);
pi.SetValue(tlpMyPanel, true, null);

ولسوء الحظ، فإن النصيحة الوحيدة التي يمكنني تقديمها هي الاهتمام بوضع عناصر التحكم بنفسك.في تجربتي، فإن .NET TableLayoutPanel، على الرغم من أنه مفيد جدًا، إلا أنه يسرب شيئًا ما ويصبح بطيئًا بشكل غير قابل للاستخدام مع نموه (ولا يتطلب الأمر عددًا غير معقول من الخلايا للوصول إلى هذه النقطة أيضًا).يمكن رؤية هذا السلوك في المصمم أيضًا.

يعمل TableLayoutPanel.Controls.Clear() بشكل جيد بالنسبة لي، ربما لأنني قمت بمسحه من علامة تبويب مختلفة عن تلك المعروضة فيه.

List<Control> controls = new List<Control>();
foreach (Control control in tableLayoutPanelEnderecoDetalhes.Controls)
{
    controls.Add(control);
}

foreach (Control control in controls)
{
    control.Dispose();
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top