none
propertyGrid Einstellung ändern RRS feed

  • Frage

  • Hallo,

    ich habe letztes ja schon einge Frage zu diesem propertyGrid gehabt. Nun eine weitere :)

     [CategoryAttribute("Allgemeine Einstellungen"),
            ReadOnlyAttribute(false),
            DefaultValueAttribute("bla)]
            public string GreetingText
            {
                get { return text; }
                set { text= value; }
            }
    

    Kann ich diesen ReadOnlyAttribute in einer anderen Klasse ändern, als ich der AppSettings.cs? Geht darum, wenn ein Anweder am Program X umstellt, soll dieser Wert im propertyGrid nicht mehr geändert werden können. Sprich das ReadOnly auf true setzen aus FormX, möglich? Kann in allen Forms/Klassen die Inhalte ändern, aber nicht die Attribute.

    Freitag, 25. November 2011 07:32

Antworten

  • Hallo,

    Warum veränderst Du nicht einfach den Setter so, dass vor dem Setzen der Eigenschaft überprüft wird, ob die Eigenschaft schon mal geändert wurde. Normalerweise wird dazu in der Datenbindung IEditableObject implementiert, aber da Du schon INotifyPropertyChanged nicht gern verwenden wolltest (?), tut's auch ein einfaches boolsches Feld:

    bool isPropertySet = false;
    
    public string GreetingText {
       get { return text; }
       set {
          if(!isPropertySet)  // setter guard
          {
             text= value; 
             isPropertySet = true;
          {
       }
    }
    
    
    

    Nun kann der Wert der Eigenschaft ein einziges Mal gesetzt werden (und je nachdem wie Du die Daten gebunden hast, wird das auch im PropertyGrid erkenntlich werden oder nicht).

    Möchtest Du hingegen einzelne Einträge im PropertyGrid sichtbar deaktivieren, dann mußt Du den Weg über Reflection nehmen, da das Steuerelement dies nicht direkt unterstützt:

    class AppSettings { 
        private string text = "Standardwert";
    
        [CategoryAttribute("Allgemeine Einstellungen"), ReadOnlyAttribute(false), DefaultValue("Standardwert")]
        public string GreetingText {
            get { return this.text; }
            set { 
                this.text= value;
                SetReadOnly(this, "GreetingText");
            }
        }
    
        private void SetReadOnly(object selectedObject, string propertyName) {
            if (selectedObject != null) {
                PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(selectedObject.GetType());
                PropertyDescriptor descriptor = properties.Find(propertyName, false);
    
                if (!descriptor.IsBrowsable)
                    return;
    
                ReadOnlyAttribute readOnlyAttribute = descriptor.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
    
                if (readOnlyAttribute != null) {
                    FieldInfo field = readOnlyAttribute.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
                    field.SetValue(readOnlyAttribute, true, BindingFlags.NonPublic | BindingFlags.Instance, null, null);
                }
            }
        }
    }
    


    Gruß
    Marcel





    Samstag, 26. November 2011 15:36
    Moderator

Alle Antworten

  • Hallo,

    Warum veränderst Du nicht einfach den Setter so, dass vor dem Setzen der Eigenschaft überprüft wird, ob die Eigenschaft schon mal geändert wurde. Normalerweise wird dazu in der Datenbindung IEditableObject implementiert, aber da Du schon INotifyPropertyChanged nicht gern verwenden wolltest (?), tut's auch ein einfaches boolsches Feld:

    bool isPropertySet = false;
    
    public string GreetingText {
       get { return text; }
       set {
          if(!isPropertySet)  // setter guard
          {
             text= value; 
             isPropertySet = true;
          {
       }
    }
    
    
    

    Nun kann der Wert der Eigenschaft ein einziges Mal gesetzt werden (und je nachdem wie Du die Daten gebunden hast, wird das auch im PropertyGrid erkenntlich werden oder nicht).

    Möchtest Du hingegen einzelne Einträge im PropertyGrid sichtbar deaktivieren, dann mußt Du den Weg über Reflection nehmen, da das Steuerelement dies nicht direkt unterstützt:

    class AppSettings { 
        private string text = "Standardwert";
    
        [CategoryAttribute("Allgemeine Einstellungen"), ReadOnlyAttribute(false), DefaultValue("Standardwert")]
        public string GreetingText {
            get { return this.text; }
            set { 
                this.text= value;
                SetReadOnly(this, "GreetingText");
            }
        }
    
        private void SetReadOnly(object selectedObject, string propertyName) {
            if (selectedObject != null) {
                PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(selectedObject.GetType());
                PropertyDescriptor descriptor = properties.Find(propertyName, false);
    
                if (!descriptor.IsBrowsable)
                    return;
    
                ReadOnlyAttribute readOnlyAttribute = descriptor.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
    
                if (readOnlyAttribute != null) {
                    FieldInfo field = readOnlyAttribute.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
                    field.SetValue(readOnlyAttribute, true, BindingFlags.NonPublic | BindingFlags.Instance, null, null);
                }
            }
        }
    }
    


    Gruß
    Marcel





    Samstag, 26. November 2011 15:36
    Moderator
  • Ich denke, dass ich deine zweite Möglichkeit brauche. Habe mal das ganze reinkopiert, allerdings fehlt mir wohl ein using, weil FieldInfo und Bindingflags nicht gefunden werden.

    Wie gesagt, wenn ein bestimmter Wert in einer ComboBox ausgewählt wird, soll im property eine Eigenschaft als ReadOnly stehen, da es in diesem Modus nicht geändert werden darf.

    Montag, 28. November 2011 08:51
  • Die Dokumentation hilft auch da weiter. FieldInfo und BindingFlags befinden sich im Namensraum System.Reflection. Wenn Du im Visual Studio Editor den Cursor auf FieldInfo plazierst und dann STRG + . drückst, erscheint ein Intellisense-Fenster in dem Du "using System.Reflection" anklicken kannst.

    Von der ComboBox höre ich erst jetzt, aber natürlich kannst Du im entspr. Handler die o.g. Logik ganz einfach implementieren.

    Montag, 28. November 2011 08:59
    Moderator
  • Hallo as_1985,

    Ist es dir inzwischen gelungen, die Zeile "using System.Reflection;" in dein Quellcode einzupflegen ;-)

    Gruß
    Marcel

    Dienstag, 29. November 2011 12:46
    Moderator
  • Hallo,

    sorry war eine längere Zeit nicht da - die Frage ist noch aktuell, habe bisher keine Lösung.

    Montag, 12. Dezember 2011 13:11
  • Du kannst die Attribute nur in einer abgeleitetet Klasse ändern.

    Hier ein Beispiel:

        public class Foo
        {
            private string _myProperty;
    
            [ReadOnly(false)]
            public string MyProperty
            {
                get
                {
                    return _myProperty;
                }
                set 
                {
                    _myProperty = value;
                }
            }
        }
        public class Foo2 : Foo 
        {
            [ReadOnly(true)]
            public new string MyProperty
            {
                get
                {
                    return base.MyProperty;
                }
                set
                {
                    base.MyProperty = value;
                }
            } 
        }
    



    Schau dir dazu nochmal diesen Link an:

    http://www.codeproject.com/KB/cs/wdzpropertygridutils.aspx

     

    Dienstag, 13. Dezember 2011 07:58
  • Gut ich habe ja bereits mehrere Klassen und Forms und kann jeden Wert des propertys auch ausserhalb der AppSettings.cs ändern. Hier kurz ein kleiner Auszug:

    // IAppSettings
    
    public interface IAppSettings
    {
         string GreetingText { get; set; }
    }
    
    // AppSettings.cs
    
    [CategoryAttribute("Allgemeine Einstellungen"),
    ReadOnlyAttribute(false),
    DefaultValueAttribute("bla)]
    public string GreetingText
    {
          get { return text; }
          set { text = value; }
    }
    
    public static AppSettings Instance
    {
          get { if (instance == null)
                  {
                      instance = new AppSettings();
                   }
                   return instance;
                }
         }
    }
    
    // Form1.cs
    
    public partial class Haupt_GUI : Form, IAppSettings
    {
        public string GreetingText   {
           get { return AppSettings.Instance.GreetingText; }
           set { AppSettings.Instance.GreetingText = value;
                    this.propertyGrid1.SelectedObject = AppSettings.Instance;
                }
            }
    
    

    Das ReadOnly Attribut soll aus Form1 geändert werden können. Kannst du mir ein passendes Beispiel zu meinem Quelltext geben? Mit diesem base.MyProperty etc. erhalte ich doch kein ReadOnly? Das von codeproject hatte ich mir bereits angesehen, Jedoch versteh ich das nicht wirklich.

    Dienstag, 13. Dezember 2011 08:47
  • Hallo as_1985,

    Was soll der Quatsch? - Du hattest bereits eine Lösung.
    Die scheiterte wohl daran, dass Du kein "using System.Reflection" in dein Quellcode einfügen konntest oder wolltest.
    Darf ich dich erinnern?

    as_1085 schrieb:
    "denke, dass ich deine zweite Möglichkeit brauche. Habe mal das ganze reinkopiert, allerdings fehlt mir wohl ein using, weil FieldInfo und Bindingflags nicht gefunden werden."

    Gruß
    Marcel

    Dienstag, 13. Dezember 2011 08:54
    Moderator
  • ??? Wo ist dieser Beitrag? Ich kann mich an sowas erinnern, aber ich kann diesen Beitrag nirgendwo mehr sehen?
    • Bearbeitet as_1985 Dienstag, 13. Dezember 2011 09:05
    Dienstag, 13. Dezember 2011 09:01
  • Laut deinen eigenen Aussagen: In deinem Quellcode.
    Dienstag, 13. Dezember 2011 09:04
    Moderator
  • Ja, wie gesagt ich kann mich erinnern - damals tat es nicht und habe es rausgeworfen. Wollte jetzt daran weitermachen, aber der post mit der Lösung ist hier nicht mehr (zumindest für mich) Sichtbar.
    Dienstag, 13. Dezember 2011 09:07
  • Ich hatte auf dein Posting zeitnah reagiert und dir in allen Einzelheiten beschrieben, wie Du ganz einfach ein "using System.Reflection" in dein Quellcode einfügen kannst. Nach diesem Beitrag warst Du noch oft im Forum, hast auf andere Fragen geantwortet etc., aber nicht auf die Antwort, die ich gepostet hatte. Dieses Desinteresse führte dazu, dass ich meine Beiträge aus diesem Thread wieder entfernt habe. Dass Du meinen Code aus deinem Quellcode "rausgeworfen" hast, spricht weiterhin über die Ernsthaftigkeit deines Unterfangens. Wer in diesem Forum postet, sollte schon selbständig ein "using System.Reflection" einfügen können. Sorry. Du nimmst meine Zeit in Anspruch, einen gewissen Respekt erwarte ich schon.
    Dienstag, 13. Dezember 2011 09:19
    Moderator
  • Ja, dass ich noch öfters (wenigstens ab und zu) hier war stimmt, aber wenn du schaust, es gab keine Beiträge zu meinem Projekt - habe nur mal geantwortet, wenn ich mal bisschen Zeit hatte. Mein Projekt lag bis gestern auf Eis... Das ich respekt vor dir und anderen Forenteilnehmer habe ist wohl klar - ich weiß wielange es dauert extra einen passenden Quelltext zu schreiben, oder Links zu suchen, ich habe mich bisher auch immer höflich bedankt. Tut mir Leid deine Zeit damals verschwendet zu haben, ich habe es damals nur wieder aus meinem Quelltext genommen, weil ich einige Errors hatte und ich mein Programm noch ausführen wollte. ich dachte, ich kann es zur gegebener Zeit wieder Einbinden, mit diesem using (wovon ich anfangs nicht wußte was man einfügen muss).
    Dienstag, 13. Dezember 2011 09:27
  • Vielleicht kann ja Robert die Beiträge für dich wieder zugänglich machen, was mich angeht ist meine Teilnahme an diesem Thread hiermit beendet.

    Dienstag, 13. Dezember 2011 10:36
    Moderator
  • Hallo Marcel,

    Ja ich kann sie machen wenn Du möchtest damit wir diesen Thread beenden können und damit er wieder übersichtlicher aussieht.

    Danke und Grüße,

    Robert

    Dienstag, 13. Dezember 2011 10:39
    Moderator
  • Hallo as_1985,

    Denke daran:

    Feedback (Rückmeldung) muss rechtzeitig kommen.

    Feedback muss erwünscht sein, das bedeutet man sollte darauf achten, dass es die anderen die mitlesen auch haben möchten.

    Feedback muss weiterhelfen, zum Beispiel für die nächste Besprechung (für den nächsten Beitrag).

    Feedback muss grundsätzlich konstruktiv sein.

    Ich danke Dir für Dein Verständnis.

    Grüße,

    Robert

    Dienstag, 13. Dezember 2011 10:59
    Moderator
  • So danke,

    leider bringt es noch nicht den komplett gewünschten Erfolg, so wie es jetzt ist kann ich genau 1x den Wert ändern und danach wird es als readonly, schonmal super :)

    Jedoch sollte es so sein, dass ein Anwender diesen Wert beliebig oft ändern kann/darf. Wenn der User allerdings eine File lädt (per Button klick), werden die Werte im propertyGrid entsprechend angepasst, ab dann darf der User keine Eingaben mehr verändern, also dann das readonly setzen.

    Danke Roma, danke Robert für das Aufheben.


    ** update **

    Eigentlich dürfte das ganze recht Einfach gehen oder nicht? Wenn ich der AppSettings eine bool Variable verpasse, die ich aus FormX ändere und sobald true => setReadOnly.

    • Bearbeitet as_1985 Dienstag, 13. Dezember 2011 11:20
    Dienstag, 13. Dezember 2011 11:16
  • So jetzt nochmal, die Lösung Nr. 2 von Roma funktioniert. Jedoch erhalte ich sofort nach jeder Änderung das ReadOnly Attribut.

    Es sollte so ein, wenn aus Form1 der Laden Button gedrückt wird, sollen sich die entsprechenenden Einträge Sichtbar auf ReadOnly gesetzt werden.

    Hier nochmals der Gesamte relevante Quelltext. Habe das Antwort Tag nur aufgehoben, dass vielleicht auch andere noch reinschauen.

     

    // IAppSettings
    public interface IAppSettings
    {
       string GreetingText { get; set; }
    }
    
    // AppSettings.cs
    public class AppSettings 
    {
        private string text = "";
    
        [CategoryAttribute("Allgemeine Einstellungen"),
         ReadOnlyAttribute(false),
         DisplayName("Greeting Text"),
         DefaultValueAttribute("")]
         public string GreetingText
        {         
            get { return text; }                   
            set {
                     text = value; 
                     // Lösung Roma
                     // SetReadOnly(this, "GreetingText");                 
                 }
        }
    
       // Lösung Roma
               private void SetReadOnly(object selectedObject, string propertyName)
            {
                if (selectedObject != null)
                {
                    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(selectedObject.GetType());
                    PropertyDescriptor descriptor = properties.Find(propertyName, false);
    
                    if (!descriptor.IsBrowsable)
                        return;
    
                    ReadOnlyAttribute readOnlyAttribute = descriptor.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
    
                    if (readOnlyAttribute != null)
                    {
                        FieldInfo field = readOnlyAttribute.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
                        field.SetValue(readOnlyAttribute, true, BindingFlags.NonPublic | BindingFlags.Instance, null, null);
                    }
                }
            }
    }
    
    // Form1.cs
    public partial class Form1 : Form, IAppSettings
        {
            // Für Änderung des Standardwertes der Klasse AppSettings
            public string GreetingText
            {
                get { return AppSettings.Instance.GreetingText; }
                set { AppSettings.Instance.GreetingText = value;
                    this.propertyGrid1.SelectedObject = AppSettings.Instance;
                    
                }
            }
    
    private void bTnLoad_Click(object sender, EventArgs e)
    {
            GreetingText = "irgendein Text";
            // Hier sollte nun das readOnly gesetzt werden
    }
    
    
    

     


    Ich habe es über die gleiche Logik versucht, wie mit dem setzen von GreetingText, sprich eine bool Variable angelegt und diese dann bei Load_Click auf true gesetzt und in der AppSettings.cs dann per if (geladen = true) { SetReadOnly....; }. Funktioniert nicht 100%, da erst nach zweimlaigen Laden das GridItem auf readOnly gesetzt wurde und darüber hinaus, dass die Variable "geladen" in dem propertyGrid erschien, was nicht sein soll.

    Vielleicht kann noch einer Helfen. Vielen Dank schonmal




    • Bearbeitet as_1985 Dienstag, 13. Dezember 2011 13:13
    Dienstag, 13. Dezember 2011 13:11
  • Kann man im propertyGird einzlene Kategorien oder Properties "nicht anzeigen"? Damit hätte ich mein oben genanntes Problem gelöst, funktioniert jetzt wie es sein sollte - musste aber dafür wie gesagt ein weiteren property Wert eintragen der leider auch im grid erscheint :)
    Mittwoch, 14. Dezember 2011 06:33