سؤال

أنا إنشاء البرنامج حيث أن المستخدم لديه خيار إنشاء الخاصة بهم الخصائص المخصصة التي من شأنها في نهاية المطاف أن يتم عرضها في PropertyGrid.الآن لا تريد الفوضى مع العرف المحررين ، لذلك أنا فقط السماح نوع بدائي خصائص (string, int, double, DateTime, bool .... الخ) أن PropertyGrid بالفعل قد بنيت في المحررين.

ولكن أريد أيضا أن تعطي المستخدم خيار إنشاء الاختيار من متعدد الخصائص حيث يمكن تعريف قائمة من القيم الممكنة والتي بدورها سوف تظهر قائمة منسدلة في PropertyGrid.

عندما كنت بجد المدونة Enum في بلدي رمز الشبكة الخاصية تلقائيا وتظهر خصائص هذا enum مثل قائمة منسدلة.ولكن يمكن إنشاء أو تعديل التعداد في وقت التشغيل بحيث يمكن للمستخدم إضافة عقار آخر خيار و العودة إلى PropertyGrid ورؤية خيار جديد في القائمة ؟

التحديث

معتبرا باتريك التعليق, أنا أفكر Enumالصورة ليست الطريقة المناسبة في هذه الحالة.لذا بدلا من ذلك كيف يمكنني استخدام قائمة سلاسل لنشر المنسدلة في PropertyGrid البند ؟ من شأنها أن تتطلب مخصص محرر ؟

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

المحلول

الجواب في فئة بسيطة: Typeconverter.. وبعد (ونعم، تعال ليست مناسبة هنا).

نظرا لأنني ليس لدي الكثير من التفاصيل، فسوف أفترض أن لديك خصائص "مرتبط" بمثيل استهداف من قبل خاصية SearseObject وأن مثيلك المستهدف ينفذ Isustomypedescriptor بحيث يمكنك إضافة خصائص (أي PropertyDescriptors) في وقت التشغيل. لا أعرف التصميم الخاص بك ولكن إذا كنت لا تفعل ذلك مثل هذا، فقد أنصحك بإلقاء نظرة عليه.

الآن دعنا نقول أنك تقوم بإضافة خاصية سلسلة وأنك تريد السماح لمستخدمك بتحديد مجموعة من القيود هذه الخاصية. UI الخاص بك دعنا المستخدم يدخل مجموعة من السلاسل وحصلت على قائمة بالسلاسل نتيجة لذلك. ربما يمكنك الاحتفاظ في قاموس الخصائص في مثيلك المستهدف، لذلك دعونا نفترض أن هذه القائمة الجديدة يتم تخزينها هناك أيضا.

الآن، ما عليك سوى كتابة محول جديد مشتق من Typeconverter (أو StringConverter ربما في هذا المثال). يجب عليك تجاوز GetStandardValuessUpported للعودة إلى TRUE و getstandardardvalues. لإرجاع قائمة السلاسل (استخدم معلمة السياق للوصول إلى خاصية المثيل وقائمة سلاسلها). سيتم نشر هذا المحول عن طريق الخصائص الخاصة بك مع خاصية PropertyDescriptor.converter.

آمل أن يكون هذا غير غامض للغاية. إذا كان لديك سؤال محدد في هذه العملية، فقط اسمحوا لي أن أعرف.

نصائح أخرى

الحل الهندسي النموذجي لمشكلتك هو استخدامها للحفاظ على القائمة كبيانات مرجعية في قاعدة البيانات الخاصة بك. بشكل عام، تهدف العادة العامة إلى أن تكون ثوابت محددة في وقت الترجمة، ويعد تعديلها في إصدار التعليمات البرمجية لاحقا (ناهيك عن وقت التشغيل)، حيث يمكن أن يسبب آثار جانبية في تبديل البيانات.

يمكنك إنشاء رمز باستخدام التعليمات البرمجية الخاصة بك، ثم احفظه على ملف نصي مؤقت، ثم استخدمه. سيكون هذا بطيئا لأنه ينطوي على استخدام HDD. أود أن أوصي بالنظر إلى انعكاس.

يحرر: لقد وجدت المثال المثالي في أحد كتبي، هنا هو (إنه مطول جدا ولكن إذا قمت بنسخه إلى مقابل VS، فسيكون من المعلن أكثر).

namespace Programming_CSharp
{
   using System;
   using System.Diagnostics;
   using System.IO;
   using System.Reflection;
   using System.Reflection.Emit;
   using System.Threading;

   // used to benchmark the looping approach
   public class MyMath
   {
      // sum numbers with a loop
      public int DoSumLooping(int initialVal)
      {
         int result = 0;
         for(int i = 1;i <=initialVal;i++)
         {
            result += i;
         }
         return result;
      }
   }

   // declare the interface
   public interface IComputer
   {
      int ComputeSum(  );
   }

   public class ReflectionTest
   {
      // the private method which emits the assembly
      // using op codes
      private Assembly EmitAssembly(int theValue)
      {
         // Create an assembly name
         AssemblyName assemblyName = 
            new AssemblyName(  );
         assemblyName.Name = "DoSumAssembly";

         // Create a new assembly with one module
         AssemblyBuilder newAssembly =
            Thread.GetDomain(  ).DefineDynamicAssembly(
            assemblyName, AssemblyBuilderAccess.Run);
         ModuleBuilder newModule =
            newAssembly.DefineDynamicModule("Sum");

         //  Define a public class named "BruteForceSums " 
         //  in the assembly.
         TypeBuilder myType =
            newModule.DefineType(
            "BruteForceSums", TypeAttributes.Public);

         // Mark the class as implementing IComputer.
         myType.AddInterfaceImplementation(
            typeof(IComputer));

         // Define a method on the type to call. Pass an
         // array that defines the types of the parameters,
         // the type of the return type, the name of the 
         // method, and the method attributes.
         Type[] paramTypes = new Type[0];
         Type returnType = typeof(int);
         MethodBuilder simpleMethod =
            myType.DefineMethod(
            "ComputeSum",
            MethodAttributes.Public | 
            MethodAttributes.Virtual,
            returnType,
            paramTypes);

         // Get an ILGenerator. This is used
         // to emit the IL that you want.
         ILGenerator generator = 
            simpleMethod.GetILGenerator(  );

         // Emit the IL that you'd get if you 
         // compiled the code example 
         // and then ran ILDasm on the output.

         // Push zero onto the stack. For each 'i' 
         // less than 'theValue', 
         // push 'i' onto the stack as a constant
         // add the two values at the top of the stack.
         // The sum is left on the stack.
         generator.Emit(OpCodes.Ldc_I4, 0);
         for (int i = 1; i <= theValue;i++)
         {
            generator.Emit(OpCodes.Ldc_I4, i);
            generator.Emit(OpCodes.Add);

         }

         // return the value
         generator.Emit(OpCodes.Ret);

         //Encapsulate information about the method and
         //provide access to the method's metadata
         MethodInfo computeSumInfo =
            typeof(IComputer).GetMethod("ComputeSum");

         // specify the method implementation.
         // Pass in the MethodBuilder that was returned 
         // by calling DefineMethod and the methodInfo 
         // just created
         myType.DefineMethodOverride(simpleMethod, computeSumInfo);

         // Create the type.
         myType.CreateType(  );
         return newAssembly;
      }

      // check if the interface is null
      // if so, call Setup.
      public double DoSum(int theValue)
      {
         if (theComputer == null)
         {
            GenerateCode(theValue);
         }

         // call the method through the interface
         return (theComputer.ComputeSum(  ));
      }

      // emit the assembly, create an instance 
      // and get the interface
      public void GenerateCode(int theValue)
      {
         Assembly theAssembly = EmitAssembly(theValue);
         theComputer = (IComputer) 
            theAssembly.CreateInstance("BruteForceSums");
      }

      // private member data
      IComputer theComputer = null;

   }

   public class TestDriver
   {
      public static void Main(  )
      {
         const int val = 2000;  // Note 2,000

         // 1 million iterations!
         const int iterations = 1000000;
         double result = 0;

         // run the benchmark
         MyMath m = new MyMath(  ); 
         DateTime startTime = DateTime.Now;            
         for (int i = 0;i < iterations;i++)
            result = m.DoSumLooping(val);
         }
         TimeSpan elapsed = 
            DateTime.Now - startTime;
         Console.WriteLine(
            "Sum of ({0}) = {1}",val, result);
         Console.WriteLine(
            "Looping. Elapsed milliseconds: " + 
            elapsed.TotalMilliseconds + 
            " for {0} iterations", iterations);

         // run our reflection alternative
         ReflectionTest t = new ReflectionTest(  );

         startTime = DateTime.Now; 
         for (int i = 0;i < iterations;i++)
         {
            result = t.DoSum(val);
         }

         elapsed = DateTime.Now - startTime;
         Console.WriteLine(
            "Sum of ({0}) = {1}",val, result);
         Console.WriteLine(
            "Brute Force. Elapsed milliseconds: " + 
            elapsed.TotalMilliseconds  + 
            " for {0} iterations", iterations);
      }
   }
}

الإخراج: مجموع (2000) = 2001000
حلقات. milliseconds المنقضي:
11468.75 ل 1000000 التكرارات
مجموع (2000) = 2001000
القوة الغاشمة. milliseconds المنقضي:
406.25 مقابل 1000000 تكرارات

هنا هو رابط للفصل بأكمله إذا كنت ترغب في مزيد من المعلومات.

يمكنك استخدام التعداد.GetNames() و التعداد.GetValues() لإستعادة القيم و حيوي إضافة جديدة لهم.على الرغم من أنني أقترح عليك استخدام قائمة بدلا من التعداد أو التفكير في التصميم الخاص بك.شيء لا رائحة الحق.

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