Laden...

Forenbeiträge von trashkid2000 Ingesamt 156 Beiträge

04.12.2019 - 22:18 Uhr

Hi,

ich dachte mir mal, ich poste mal ein Tutorial.
Und das für die Verwendung des WPF - Ribbon unter der Verwendung des MVVM-Pattern.

Vorwort: Es gibt von M$ ein paar Samples zu diesem Thema, eine Suche nach 'MicrosoftRibbonForWPFSourceAndSamples' findet diese.

Soweit so gut, aber dies ist nicht das, nach dem ich suchte...
In den Samples werden (umfangreiche) Objekte im ViewModel zusammengebaut. Aber MVVM-konform ist das nicht. Es ist so einfach nicht möglich, das ganze Konstrukt einfach umzubiegen...

Beruflich habe ich eine Umsetzung benötigt, in der wie gewöhnt, einfach ein ViewModel und das entsprechende DataTemplate definiert werden kann.

Also, nach ein paar fails hier eine Lösung des Ganzen.
Überschrieben wurde dabei die Definition, wie Das jeweilige ItemsControl seine Items erzeugt.

Bei dem Ribbon ist es das ControlTemplate, was bei der Erzeugung der Tabs überschrieben wurde.
Bei dem ApplicationMenu einfach der Container, der zur Anzeige eines Items erzeugt wird.


public class CustomRibbon : Ribbon
{
   /// <summary>
   /// Bereitet den RibbonTab so vor, dass der Content auf das Item gesetzt wird und ein definiertes DataTemplate zur Anzeige genutzt wird
    /// </summary>
    /// <param name="element">Der Tab, der zur Anzeige vorbereitet werden soll</param>
    /// <param name="item">Objekt, das als Content gesetzt wird</param>
    protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {
        var tab = (RibbonTab)element;

        var controlTemplate = new ControlTemplate(typeof(RibbonTab));
        var contentControlFactory = new FrameworkElementFactory(typeof(ContentControl));
        contentControlFactory.SetBinding(ContentControl.ContentProperty, new Binding() { Source = item });

        contentControlFactory.SetBinding(VisibilityProperty, new Binding() 
        { 
            UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, Source = tab, 
            Path = new PropertyPath(nameof(tab.IsSelected)), Converter = new BooleanToValueConverter() { FalseValue = Visibility.Collapsed, TrueValue = Visibility.Visible } 
        });
        
        controlTemplate.VisualTree = contentControlFactory;
        contentControlFactory.SetValue(IsTabStopProperty, false);
        tab.Template = controlTemplate;

        tab.Header = item;
   }
}


public class CustomRibbonApplicationMenu : RibbonApplicationMenu
{
   /// <summary>
   /// Erstellt einen neuen Container für einen Eintrag im Menü
   /// </summary>
    /// <returns>Den erstellten Container</returns>
   protected override DependencyObject GetContainerForItemOverride()
   {
      return new ContentControl() { IsTabStop = false };
   }

   /// <summary>
   /// Bereitet den Menüeintrag für die Anzeige vor
   /// </summary>
   /// <param name="element">Das <see cref="ContentControl"/>, das als Container genutzt wird</param>
   /// <param name="item">Der Content</param>
   protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
   {
       var contentControl = ((ContentControl)element);
       contentControl.Content = item;
    }

   /// <summary>
   /// Behebt das Verhalten, dass das Menü geschlossen wird, wenn ein Menuitem, das disabled ist, angeklickt wird.
   /// </summary>
   /// <param name="e">Die <see cref="MouseButtonEventArgs"/></param>
   protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
   {
      if (e.OriginalSource is ContentPresenter applicationMenuItemContentPresenter)
      {
         if (VisualTreeHelper.GetChild(applicationMenuItemContentPresenter, 0) is RibbonApplicationMenuItem applicationMenuItem)
         {
            if (!applicationMenuItem.IsEnabled)
            {
                e.Handled = true;
             }
          }
       }

       base.OnPreviewMouseLeftButtonUp(e);
   }

   /// <summary>
   /// Behebt das Verhalten, dass in dem Menü manchmal direkt das ContentControl des ContainerForItemOverride angesprungen wurden und das AppMenuItem dann nicht fokussiert wurde. Gerade bei Up und Down war das aufgefallen.
    /// </summary>
    /// <param name="e">Die <see cref="KeyboardFocusChangedEventArgs"/></param>
    protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
    {
        if (e.OriginalSource is ContentControl contentControl)
        {
            var applicationMenuItem = (UIElement)contentControl.FindVisualChildren<DependencyObject>().FirstOrDefault(x => x.GetType().GetProperty(nameof(QuickAccessToolBarId)) != null);
            if (applicationMenuItem != null)
            {
                applicationMenuItem.Focus();
             }
         }

         base.OnGotKeyboardFocus(e);
     }
}

Eingebunden wird dies dann wie folgt:


<Controls:CustomRibbon ItemsSource="{Binding RibbonTabItems}">
   <Controls:CustomRibbon.ApplicationMenu>
      <Controls:CustomRibbonApplicationMenu ItemsSource="{Binding ApplicationMenuItems}" FooterPaneContent="{Binding CloseApplicationFooterPaneContent}" AuxiliaryPaneContent="{Binding AuxiliaryPaneContent}"/>
   </Controls:CustomRibbon.ApplicationMenu>
</Controls:CustomRibbon>

Ein Sample-Projekt kann unter
https://drive.google.com/file/d/1d2OckuDTLwnZ86p50Keyh_67zz2eWwFC/view?usp=sharing
heruntergeladen werden.

Viel Spaß damit,
Marko

06.05.2019 - 22:49 Uhr

Hi,

es reicht nicht, einfach nur von RadioButton zu erben und in der vererbten Klasse Methoden zu überschreiben. Denn so änderst Du nur das Verhalten.

Was Du machen möchtest, ist, dass Du das Aussehen verändern willst (ja, und das Verhalten).

Da kommst Du nicht drum rum, das ControlTemplate zu überschreiben.
Eine gute Übersicht findest Du hier: RadioButton Styles und Templates

lG, Marko

30.04.2019 - 23:20 Uhr

Hi,

ich hatte zwischenzeitlich auch mal VS 2019 ausprobiert...
Nach ein wenig Arbeit habe ich mir nun wieder VS 2017 installiert. Dank Side by Side ja zum Glück möglich 😃

Ich hatte die genannten Probleme auch.
Das war bei einer WPF-Bibliothek, bei der ich eine neues Control eingefügt habe.
Und dieses bei dem referenzierten Projekt einfach nicht erkannt wurde...

Nach gefühlten 10x Clean, Rebuild, schließen und öffnen von VS und erneutem Laden der Solution ging es dann irgendwann.
Ich konnte damals das Problem nicht wirklich eingrenzen.

Nachdem mir dann irgendwann die gesamte Solution mit Fehlern, die nicht ersichtlich waren, um die Ohren flog, habe ich den Entschluss gefasst, zurück zu rudern.

11.04.2019 - 22:53 Uhr

Hi Abt 🙂

Du kannst die Bibliothek höchstens irgendwo referenzieren und dann in .NET Core, .NET Framework... ausführen.
Daher in der Form der Erklärung eigentlich nur zwei potentielle Ursachen:

  • Unterschiedene der referenzierten Pakete

Ja, die NETStandard-Bibliothek wird in ein .NET Framework-Projekt refrenziert.

Und genau, der Unterschied liegt in dem von dem Package referenzierten Pakete:

Unter .NET Framework 4.6 sind es diese:
System.Security.Cryptography.Encoding (≥ 4.3.0)
System.Security.Cryptography.X509Certificates (≥ 4.3.0)

Unter .NETStandard 2.0 diese:
System.Buffers (≥ 4.4.0)
System.Security.Cryptography.Cng (≥ 4.4.0)
System.Memory (≥ 4.5.1)

Ab .NET Framework 4.6.1 gibt es keine Abhängigkeiten mehr...

Ich habe es zum Laufen gebracht, indem nun die Assembly, die für NETStandard 2.0 gedacht ist, sowie alle da abhängigen Assemblies, geladen werden.

Aber so ganz verstehen tue ich es trotzdem nicht 🤔
lG, Marko

//EDIT: Ich werde mal ein konkretes Beispiel nachstellen

11.04.2019 - 06:45 Uhr

Hi Abt,

.NET Standard ist nur ein Vertrag - keine Runtime.
.NET Standard ist aus C# sicht als Interface zu sehen, während .NET Framework, Mono, Xamarin, .NET Core.. als konkrete Implementierung zu sehen sind.

Soweit dachte ich auch. Wie gesagt, die API auf dem Server ist gege .NET CORE 2.x entwickelt.

Die Frage ist hier also eher, ob sich jede Runtime identisch verhält.

Konkretes Beispiel?

>

Das habe ich mir gestern gebaut, in dem ich eine dumme Consolen-App geschrieben habe, die unter .NET Framework 4.6 läuft, und einmal ein Binary vom Server mit Framework-Bordmitteln entschlüsselt. Da kommt das Besagte bei raus.
Zusätzlich inkludiert das Testprojekt noch eine netStandard-Bibliothek in 2.0, wo genau das Gleiche getan wird.
Und da passt es dann 🤔
Wenn ich heute mal dazu komme, werde ich es hier mal posten.
Danke erstmal, Marko

10.04.2019 - 22:19 Uhr

Hi,

ich kämpfe nun schon eine ganze Weile, und es bringt mich bald um den Verstand....
Wir haben eine API, die unter .NET Core 2.1 läuft, und unter anderem Daten verschlüsselt....
Das macht die Bibliothek 'System.Security.Cryptography.Pkcs'. Diese erstellt eine verschlüsselte Nachricht für ein oder mehrere Empfänger. Per nuget eingebunden.
Soweit alles gut, läuft 🙂

Auf Clientside empfangen wir die Nachrichten und müssen sie auch wieder entschlüsseln.
Und genau hier gehen die Probleme los...

Der Client ist gegen .NET Framework 4.7 programmiert. Die oben genannte Bibliothek ist in der gleichen Version per nuget eingebunden, aber es verhält sich anders...
So können die verschlüsselten Werte auch wieder entschlüsselt werden, aber der Wert, der da raus fällt, passt nur so halb.

Es sind immer irgendwelche Sonderzeichen am Anfang drin...
Das scheint irgendwie ein Codierungs-Problem zu sein. Aber wir benutzen überall UTF8.
Gegen netStandard 2.0 können die Werte ganz normal entschlüsselt werden.

Ich sehe auch, dass das Package je nach Framework unterschiedliche Assemblies einbindet, vielleicht liegt darin das Problem??

Ist da was bekannt?
Für Antworten bin ich sehr dankbar,
lG Marko

05.04.2019 - 23:19 Uhr

Ich sehe da eindeutig zu viele

KillTasks();
05.04.2019 - 23:17 Uhr

Hallo,

also sowas ist böse:

comboBox_SampleFreq.SelectedIndex=i;

Was der User ausgewählt hat, solltest Du so belassen. Das gibt sonst nur Probleme.
Und wozu das?

Viel schlimmer ist aber noch das:


if (Gen.StandardError.Peek()>0)
{
   comboBox_SampleFreq.Items.RemoveAt(i--);
}

Was kann die "arme ComboBox" dafür, dass Fehler auftreten? Die Items sollten hier ziemlich konstant sein!

05.04.2019 - 23:00 Uhr

Hi, das Argument bei der Methode


rand.Next(...);

verlangt einfach mal einen maxValue. Und der darf nicht kleiner als 0 sein.
Du kannst aber den Wert auch einfach umformen und dann * -1 rechnen 😉

lG, Marko

28.03.2019 - 21:52 Uhr

Hi Abt,

vielen Dank erstmal für Deinen Beitrag 👍

Das Problem von JavaScript ist aber, dass es teilweise einfach eine Hassliebe ist; und, dass JavaScript eben im Plaintext auf dem Client verarbeitet wird.

Genau so ist es... die Liebe dazu und der Hass dagegen, das sind wirklich Welten...

Damit wäre ein weiterer Schritt gegeben, dass heutige Web-Technologien mehr und mehr auf dem Desktop ankommen.

Ein sehr guter Weg in die richtige Richtung.
Aber ich sehe es nicht kommen, das man mit einer SPA alles machen kann, was man halt mit einer Desktop-App machen kann.

Denn irgendwie bist Du ja immer im Browser gefangen... das hoffe ich doch zumindest !!

Marko

26.03.2019 - 21:42 Uhr

Hi,

okay, vielen Dank für die Antwort erstmal 🙂
Für alle, die das gleiche Problem haben, wirklich sehr hilfreich 👍

Aber was die Bibliothek anders macht, das kannst Du nicht evaluieren?

21.03.2019 - 23:27 Uhr

Um den Fehler eingrenzen zu können, müsste man sich wohl mal das ganze Netzwerkprotokoll ansehen... also wirklich, was sendet der Client, und was bekommt er dann vom Server.

Sonst ist das alles nur ganz viel rätselraten...

21.03.2019 - 23:22 Uhr

Interessant wäre ja hier, was Du versucht hast...
Was ist denn "Alles"?

19.03.2019 - 22:12 Uhr

Hi,

das ist schön 🙂
Und für alle, die das gleiche Problem bzw. die gleiche Frage haben, wäre es sehr klasse, wenn Du Deine Lösung posten könntest 👍

Marko

17.03.2019 - 21:40 Uhr

Hi,

Wie könnte ich das ganze automatisiert alle 10 Sekunden pro Row ausführen lassen?

Also automatisiert alle 10 Sekunden, bei einem WebRequest finde ich sehr sportlich.
Mit Threading bestimmt machbar, aber ja:

Was soll das Programm denn machen?

//// edit: Du verwendest doch nie das Result, was Du durch den WebRequest absendest... 🤔

05.03.2019 - 22:40 Uhr

Also:
ich entwickle einen barrierefreien Texteditor mit Microsoft Dotnet WPF.
der kommt auf meine Webseite zum kostenlosen Download.

Auch wirklich nicht böse gemeint, aber ich persönlich bleibe ganz sicher, wenn ich das hier so lese, bei meinem Notepad++ oder Visual Studio Code.

Alle können unheimlich viel, inklusive zig PlugIns.

Und ehrlich gesagt wäre es für mich ein Totschlagkriterium, wenn sich eine Software (und am besten noch ohne Nachfrage) als Standardprogramm registrieren würde !!

Was bedeutet denn barrierefrei eigentlich im Kontext eines Editors?

Marko

20.02.2019 - 22:19 Uhr

Es gibt keine Begründung, wieso ein Programm, das unter eingeschränkten Berechtigungen laufen können muss, Schreibrechte auf sein Installationsverzeichnis haben sollte.

Ich habe ja auch nicht gesagt, dass dort ein schreibender Zugriff möglich sein soll 😉 Ja, bitte, never!!
Aber die Anwendung, die aus dem Pfad gestartet wird, sollte sehr wohl seine Application Settings laden dürfen.
Wer und wie diese geändert werden können, steht auf einem anderen Blatt.

User Settings landen natürlich im Benutzerprofil.

Es ist gefährlicher Unsinn, ApplicationSettings im Installationspfad zu hinterlegen.
LaTino 🤔 warum?

19.02.2019 - 22:52 Uhr

Hi,

von welcher Art von Konfiguration reden wir hier?
Die typische app.config?
In denen nur Application-Settings stehen?

Wer unter Windows XP oder Vista Konfigurationsdateien in das Anwendungsverzeichnis und damit in einen für den User geschützten Ordner abgelegt hat, hat es damals schon falsch gemacht.

Ach ja?
Ich bin sehr wohl der Meinung, dass eine app.config mit ApplicationSettings dort gespeichert sein sollte, wo das Programm liegt.. also meist unter C:\Programme, oder C:\Programme(x86),
(und auch nicht jeder DAU-User schreiben und etwas ändern kann)

Wo hat VS seine devenv.exe.config abgelegt??

Ein anderer Part sind User-Settings 🙂
Die gehören ganz sicher an einen Plaz, wo der User auch Schreibberechtigung hat 😉

30.01.2019 - 22:03 Uhr

Hier wieder das Rad neu zu erfinden um es wieder einmal runder zu machen zeugt meistens von mangelhafter Erfahrung was generelle und grundsätzliche Lösungswege angeht

natürlich 👍

Und nein, nach mehr als 10 Jahren damit vertraut keine mangelnde Erfahrung...
Vielleicht nur manchmal einfach (zu sehr) auf Sicherheit bedacht 😉

29.01.2019 - 22:50 Uhr

Sorry,
@Abt

Das Grundproblem ist, dass hier offensichtlich der Beschreibung nach keine Schichtentrennung erfolgt.
Es werden also Klassen zum Speichern verwendet, die UI- oder Businessmodelle darstellen.

Bzw. Businesslogik enthalten. Ja, da gebe ich Dir Recht. Das ist nicht gut.
Die DataModel-Schicht (Infrastructure, oder wie auch immer) soll also nur dumm sein. Und Daten halten.
Und im besten Fall die Daten nicht einfach von "außen" modifizierbar machen.

Ein Feld ist nur ein "dummes" Klassenmember; also eine Variable.
Eigenschaften sind jedoch Abstraktionen; Du kannst beim Setzen (oder Lesen) noch zusätzliche Dinge tun (zB Lazy Loading, Events feuern..) - was bei einem Feld nicht geht.

Das beißt sich meiner Meinung nach mit Schichtentrennung und dumme Datenklasse 😉

29.01.2019 - 22:30 Uhr

Wenn Du **Json.NET **benutzt,
gibt es da noch die Möglichkeit von private Setters:


[JsonProperty]
public Guid? ClientId { get; private set; }

Nur mal so als Anregung 🙂

// Edit: jaa...
XML und kein JSON... passt dann gar nicht

28.01.2019 - 23:08 Uhr

@trashkid2000
Sowas macht man nicht.
Dafür gibt es, wie Th69 schon sagt, einfach Eigenschaften.

Die dann aber auch public get set sein müssen...
Deswegen lasse ich es nicht so einfach stehen.
Und ja, manchmal ist für Sicherheit auch (viel) Mehraufwand nötig.

27.01.2019 - 20:57 Uhr

Hi,

wo kommt denn die Methode

Generate(..., ...)

her?

Da fehlt doch sicher ein Namespace - Import?

Gruß, Marko

25.01.2019 - 22:07 Uhr

Hi,

Du könntest einen Custom-Serializer/ Deserializer erstellen, der dann aus privaten Feldern die Daten in die XML schreibt bzw. aus dieser in die privaten Felder schreibt.

Gruß, Marko

25.01.2019 - 22:02 Uhr

Hi,

kannst Du mal ein kleines Beispielprojekt mit diesem Control online stellen?
Dann kann ich mal schauen...

lG, Marko

// edit: hat sich wohl erübrigt

24.01.2019 - 21:45 Uhr

Schaue Dir z.B. mal OData an...

24.01.2019 - 21:32 Uhr

Hi,

Die Anwendung erhält >100000-Datensätze durch diesen einen Funktionsaufruf. Jeder Entry hat hierbei ca. 200 Properties

sorry, wenn ich es so schreibe, aber bitte welche Anwendung soll speichertechnisch damit umgehen (können)? Das ist schon eine Menge !

Jetzt mal Flach dargestellt. Diese Informationen liegen verschachtelt vor

Was höchstwahrscheinlich noch viele JOINS auf Serverseite zur Folge hat...
Und Warten des Clients...

Du musst wirklich die Datenmengen begrenzen, die von dem Server abgerufen werden und durch den Client materielisiert werden !

21.01.2019 - 21:30 Uhr

Hi,

also mein erster Gedanke bei Deinen Fragen unten war, dass Du mit einem ValueConverter arbeiten könntest. Das wäre dann eine Konvertierung von Width des StackPanels, in dem die Vorschläge angezeigt werden zu max 2* Width für die TextBox.

Und ansonsten würde ich bei der TextBox dann einfach das TextWrapping einschalten.
Dann sollte es passen. Nur weiß ich nicht, wegen Popup und Visual Tree, ob Du da an die Controls ohne weiteres rankommst...

Grüße, Marko

28.12.2018 - 00:02 Uhr

SPF habe ich vorher auch noch nie gehört... klingt aber irgendwie vielversprechend !

Sicherheit ist, wenn nichts mehr geht... ! Und das habe ich die letzten Tage vor dem Weihnachtsurlaub auf Arbeit so oft gehabt.

30.11.2018 - 23:54 Uhr

Puh, wirklich? Auf diesem Niveau jetzt...? 🤔

Irgendwie bist du immer von oben herab unterwegs, eigentlich sehr schade für diese Forum!

Gerade fundierte Meinungen sind für dieses Forum (und im Allgemeinen) sehr wichtig !
Und ob von oben herab oder auf gleicher Augenhöhe liegt immer im Auge des Betrachters 😉

09.11.2018 - 23:13 Uhr

Hi,
schaue Dir mal dies an:
Why does WPF Style to show validation errors in ToolTip work for a TextBox but fails for a ComboBox?

Die Fehlermeldung ist ja eindeutig, und eine Behebung über eine Gooogle-Suche gar nicht so schwer.

lG, Marko

06.11.2018 - 21:36 Uhr

Lieben Dank 👍
Wurde auf dem ersten Blick viel InteropServices und das ISerializable bei Exceptions rausgeschmissen...

Aber auch sonst ganz viele Neuerungen, die man sich mal anschauen sollte.
Bzw. Eigenimplementierungen nun im Framework sind 🙂

29.10.2018 - 22:34 Uhr

Und wenn jemand Cheats schreiben kann, dann weiß derjenige auch wie .NET funktioniert und was ILCode ist.

Oh ja.

Von daher muss man an der Stelle ehrlich sein und Dich eher in Richtung C++ für solch ein Tool verweisen.

Und dieser weiß dann auch ganz sicher, wie man in Assembler ein paar JMP's oder NOP's einbaut...

10.10.2018 - 22:31 Uhr

Wie meinst du das, dass DLL nicht nackt verteilt werden?

Hat @Abt mit dem Stichwort NuGet gemacht.
Bedeutet, man erstellt ein NuGet-Package mit dieser dll und packt sie auf eine Package Manager Source. Muss nicht nuet.org sein, sondern auch einfach ein Netzwerklaufwerk.

Die erstellten Packages sind quasi festgefroren, und ein Client, der das Paket einbindet, schaut selbstständig, ob es eine Aktualisierung gibt, ob er mit der Aktualsierung umgehen kann, und dann aktualisiert oder eben nicht oder zu einem späteren Zeitpunkt.

07.10.2018 - 22:06 Uhr

@gfoidl:

Ich schließe mich dessen an, wir auf Arbeit verwenden auch für die Datenbank im VS ein Datenbank-Projekt, das versioniert im GIT liegt, und bei dem man bei der MigrationScript-Erstellung wenigstens volle Kontrolle hat. Und in dem man zum Hochziehen der Produktiv-Datenbank auch noch Fehlerbehandlung oder Sonderbehandlungen einbauen kann 🙂
Für eine Testdatenbank ist es mir Latte, ob da Daten flöten gehen.

Gerade bei Strukturänderungen ist es ja auch eine Frage der Berechtigungen.
Denn Anwendungen/ Services sollten meiner Meinung nach gerade mal DataReader/ DataWriter sein, mehr nicht! Und das dann auch noch eingeschränkt.

lG, Marko

05.10.2018 - 16:04 Uhr

Hi LaTino,

Kanonen und Spatzen. Setz einfach den SerializationBinder hier:

  
//Startup  
services.AddMvc().AddJsonOptions(opt => opt.SerializerSettings.SerializationBinder = new SafeTypeNameHandlingSerializationBinder());  
  

Oh, das ist natürlich ein sehr guter Einwand 👍
Stimmt, dann kann der Formatter raus... umso weniger Custom Code, umso besser...
Mit den KnownTypes könnten wir mal überlegen 🙂

Auf jeden Fall danke für den Tipp,
lG Marko

05.10.2018 - 15:19 Uhr

Hi Leute,

wir nutzen auf Arbeit bei unserer JSON-API-Schnittstelle das Feature "TypeNameHandling", da wir an der Schnittstelle vererbte Typen empfangen müssen und so Typinformationen benötigen.

Nun habe ich mal einen interessanten Artikel über JSON Exploits in dem ZUsammenhang gelesen: https://www.alphabot.com/security/blog/2017/net/How-to-configure-Json.NET-to-create-a-vulnerable-web-API.html

So war es (ich habe es auch getestet) z.B. möglich, solch einen Konstrukt an die API zu senden:


{
   "$type": "System.IO.FileInfo, System.IO.FileSystem",
   "fileName": "rce-test.txt",
   "IsReadOnly": true
}

Und wie man dann im Output gesehen hat, so wurde eine Exception geworfen, weil tatsächlich nach dieser Datei gesucht wurde und versucht wurde, diese readonly zu setzen.
Es gibt, wenn man sich mit dem Thema beschäftigt, noch ganz andere Sachen, die man von außen triggern kann... erschreckend.

Also habe ich mal ein wenig geschaut, dass ich das ganze deserialisieren sicher gestalte, indem ich einen eigenen InputFormatter benutze, der nur die Typen deserialisiert (und vor allem instanziiert), die innerhalb der Assembly definiert sind. Bei allen anderen Typen wird dann NULL zurückgegeben, was die API dann intern handelt).

Kann man das so machen? Was denkt Ihr?
Bin für ein kleines Review des Codes sehr dankbar.

Liebe Grüße, Marko


   public class SafeTypeNameHandlingJsonInputFormatter : TextInputFormatter
   {
        public SafeTypeNameHandlingJsonInputFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
            SupportedEncodings.Add(Encoding.UTF8);
        }

        public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
        {
            using (var reader = new StreamReader(context.HttpContext.Request.Body))
            {
                var content = await reader.ReadToEndAsync();
                var jObject = JObject.Parse(content);
                var typeValue = jObject["$type"]?.Value<string>();
                if (typeValue != null)
                {
                    var model = jObject.ToObject(typeof(object), new SafeTypeNameHandlingJsonSerializer());
                    return await InputFormatterResult.SuccessAsync(model);
                }

                return await InputFormatterResult.FailureAsync();
            }
        }
    }

    public class SafeTypeNameHandlingJsonSerializer : JsonSerializer
    {
        public SafeTypeNameHandlingJsonSerializer()
        {
            SerializationBinder = new SafeTypeNameHandlingSerializationBinder();
            TypeNameHandling = TypeNameHandling.Objects;
        }
    }

    public class SafeTypeNameHandlingSerializationBinder : DefaultSerializationBinder
    {
        public override Type BindToType(string assemblyName, string typeName)
        {
            try
            {
                var type = Type.GetType($"{typeName}, {assemblyName}");
                if (type != null)
                {
                    // an dieser Stelle wird geprüft, ob ein Typ deserialisiert werden soll, der innerhalb dieser Assembly deklariert wurde
                    // wenn ja, darf der geerbte DefaultSerializationBinder gerne binden, ansonsten nicht, denn dann könnte injected werden

                    var isOwnDeclaredType = Assembly.GetExecutingAssembly().GetTypes().Any(t => t == type);
                    if (isOwnDeclaredType)
                    {
                        return base.BindToType(assemblyName, typeName);
                    }
                }
            }
            catch { }

            return null;
        }
    }
   
03.10.2018 - 11:51 Uhr

@Th69:
Gut, das ist natürlich die Frage....

@TimFranke:
Also wenn Du die partielle Klasse, die der Generator erstellt erweitern willst, dann muss Deine Klasse ebenfalls partial sein, genauso heißen und auch im gleichen Namespace sein.

Also so:


namespace test01
{
    public partial class MainPage
    {
        public static void Start()
        {
            Console.WriteLine("Kontrolle");
            labeltest.Text = "Label nach dem Click";
        }
    }
}

lG, Marko

02.10.2018 - 23:58 Uhr

Hi,

also in der CodeBehind, die der Designer anlegt, gibt es dann auch Designercode, der die ganzen Controls instanziiert und initilalisiert.
Also Instanzen der Controls erzeugt, dem außenliegenden Control als Children hinzufügt und alle Eigenschaften setzt, die Du im Designer zusammengeklickt hast.

Die ganzen Controls sind Instanzen, von daher kommst Du da mit einer static class, die irgendwo herumschwirrt, gar nicht ran!

Aber zu großen Glück sind ja die generierten Klassen partial
So kannst Du die Klasse dann ganz einfach erweitern:


public partial class Form1
{
   public void Run()
   {
       MainProgressBar.Progress = 1;
   }
}

13.05.2018 - 22:11 Uhr

Ich kann da @Abt wirklich nur zustimmen.

Und gerade bei sowas...


-- VirusUploader.hef []

Marko

08.05.2018 - 22:42 Uhr

Hi,

probiere es mal mit dem UpdateSourceTrigger.


<TextBox Text="{Binding XValue, UpdateSourceTrigger=PropertyChanged}"/>

Und dazu noch


public RelayCommand SetValueCommand { get; private set; }

...

public int XValue
{
   get { return _XValue; }
   set
   {
      _XValue = value;
      SetValueCommand.RaiseCanExecuteChanged();
   }
}

Der Hintergrund dazu:
Eine TextBox in WPF schreibt per default erst bei LostFocus in das Binding zurück. Deshalb das explizite setzen auf PropertyChanged.

Das aufrufen der Methode

 RaiseCanExecuteChanged() 

des Commands - Du hast laut SourceCode das Gleiche getan, aber ich glaube zu wissen, dass der CommandManager nicht der gleiche ist...
lG, Marko

09.04.2018 - 23:24 Uhr

Ich sage mal so,
was mach denn die ConsoleApp?

Vielleicht lässt sich ja besser die Funktionalität darin parallelisieren !

03.04.2018 - 22:03 Uhr

Hi,

es hindert Dich nichts daran, von der Klasse TabPage zu erben, um zusätzliche Eigenschaften unterzubringen.


public class CustomTabPage : TabPage
{
    public string Identifier { get; set; }

     public CustomTabPage()
    {
        Controls.Add(new Label() { Text = "Hallo" });
    }
 }

Somit kannst Du dann ganz einfach Deinem TabControl die zusätzlichen Seiten hinzufügen:


   MainTabControl.TabPages.Add(new CustomTabPage() { Text = "Tab1", Identifier = "Tab1" });

Vererbung sollte bei Dir auf jeden Fall mal ein Thema sein !
lG, Marko

P.S.: Warum WinForms ? Das alles mit WPF ist viel einfacher und zukunftsweisender !

08.09.2017 - 22:09 Uhr

Was hat funktioniert?

Kannst Du mal bitte beschreiben, wo das Problem lag?
Bzw., wie Du die Lösung gefunden hast.
Damit auch andere User bei gleichen Problemen eine Lösung finden.

PS.: So wirklich habe ich aber auch nicht verstanden, was das Problem war...

05.09.2017 - 23:54 Uhr

Hallo Padman,

Es kann sein dass ich momentan nur Begriffsstutzig bin da es mir nicht so gut geht...

Dann Dir gute Besserung erstmal!

Habe mir die SampleApp auch mal angeschaut. Also es scheint so, als ob das nur aus der Registry gelesen werden kann, also vor der ersten Instanziierung eines WebBrowserControls auch dort drin stehen muss 😕
Ätzend, von der Registry bin ich überhaupt kein Freund...
lG, Marko

05.09.2017 - 23:27 Uhr

Hi,

was repräsentiert denn die Variable "j", die für die Berechnung von Top hinzugezogen wird?
Kann es sein, dass initial der Wert von Top = 0 ist?
Dann überschreibt der erste Label den Header der GroupBox.

lG, Marko

26.02.2017 - 09:35 Uhr

With a POST request you get the random Word. To inspect, use Fiddler Web Debugger

private static string GetRandomWord()
{
    var request = (HttpWebRequest)WebRequest.Create("http://watchout4snakes.com/wo4snakes/Random/RandomWord");
    request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
    request.Method = "POST";
    request.ContentLength = 0;

    using (var response = request.GetResponse())
    {
         using (var responseStream = response.GetResponseStream())
         {
              using (var responseReader = new StreamReader(responseStream, Encoding.UTF8))
              {
                   return responseReader.ReadToEnd();
              }
         }
    }
}

lG

20.12.2015 - 14:07 Uhr

Liebe Alle,

ich möchte gerne mein endecktes Wissen weitergeben, deswegen poste ich hier mal.

Vor kurzem stand ich auf Arbeit vor der Aufgabenstellung, WPF - UserControls mit Hilfe von T4 zu generieren. Also für jede Sicht nur eine .xaml - Datei. Problem dabei ist, dass man für den Aufruf von "InitializeComponent();" ja auch immer eine partial .cs benötigt. Nartürlich wäre es möglich, wenn man schon beim generieren ist, für jedes Control auch die partial -cs mit zu generieren, aber wozu? Ein genereller Weg wäre solch ein BaseUserControl:


public class BaseUserControl : UserControl
{
   public BaseUserControl()
   {
      var iComponentConnector = this as IComponentConnector;
      if (iComponentConnector != null)
      {
          iComponentConnector.InitializeComponent();
      }
   }
}

Und die generiert xaml dazu würde dann z.B. so aussehen:


<local:BaseUserControl x:Class="WpfApplication11.TestUserControl"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:WpfApplication11">

    <Grid>
        <TextBlock Text="Hallo"/>
    </Grid>
</local:BaseUserControl>

Das UserControl kann so problemlos im Designer angezeigt werden.

lG und viel Spaß beim Generieren 😃

08.08.2015 - 22:28 Uhr

Hi,
hier mal eine gute Anleitung der Einbindung des Treibers unter VS als Video.
Du musst Dir von MySql den Connector/ODBC runterladen, installieren und im System registrieren.

Youtube: MySQL in Visual Studio als Datenquelle einbinden

18.01.2012 - 11:53 Uhr

Hi,

also bloß, weil Du in irgendeiner Klasse eine static main-Methode definiert hast, heißt das noch lange nicht, dass sie automatisch der Einstiegspunkt im Programm ist und aufgerufen wird!