Laden...

Logik Steuerelemente Aktivieren / Deaktivieren per Konfigurationsdatei möglich?

Erstellt von Unfug vor 8 Jahren Letzter Beitrag vor 8 Jahren 5.044 Views
U
Unfug Themenstarter:in
133 Beiträge seit 2006
vor 8 Jahren
Logik Steuerelemente Aktivieren / Deaktivieren per Konfigurationsdatei möglich?

Hallo mycsharp,

Ich habe eine GUI (WPF), die eine Vielzahl an "Buttons" hat.

Beim Starten der Anwendung ist noch nichts geladen und ein Großteil müsste deaktiviert werden.
Genauso müsste sobald etwas in der Anwendung geladen wurde, die Buttons aktiviert werden.

Übliche Vorgehensweise wäre die Abhängigkeit in Code umzusetzen.
Beispielhaft:


if (aktiv)
{
Button1.Enabled= true;
Button2.Enabled= true;

}

else
{
Button1.Enabled = false;
}

Persönlich finde ich das ziemlich unschön. Gibt es vielleicht die Möglichkeit, dass man bei WPF diese Abhängigkeiten in eine Art XML Konfigurationsdatei schreibt und WPF diese auswertet?
Vielleicht sowas?

[Datei geladen]
[AktiveButtons]
Button1
Button2
Button3
[InaktiveButtons]
Button4
Button5

Ich hoffe ich habe es verständlich geschrieben. Auch für die weitere Entwicklung/Testen fände ich dies sehr gut, da ich so einige "Plugins" einfach ausgrauen könnte, damit man sich auf das Wesentliche fokussiert.
Hat jemand Tipps für mich?

Danke
Unfug

189 Beiträge seit 2014
vor 8 Jahren

Übliche Vorgehensweise wäre die Abhängigkeit in Code umzusetzen.
Beispielhaft:

  
if (aktiv)  
{  
Button1.Enabled= true;  
Button2.Enabled= true;  
  
}  
  
else  
{  
Button1.Enabled = false;  
}  
  

Ja, aber nicht so.
Nutze MVVM resp. CommandBinding.
Dann hast du RelayCommands, die als 1. Parameter ein Delegat für die Funktion, die Hinter dem Button steckt, und als 2. Parameter ein Delegat besitzen, der Überprüft, ob der Button aktiviert sein darf.

VG Ezio

5.299 Beiträge seit 2008
vor 8 Jahren

ähm - wenn man ein RelayCommand nutzt, dann nutzt man grade kein CommandBinding.

Der frühe Apfel fängt den Wurm.

U
Unfug Themenstarter:in
133 Beiträge seit 2006
vor 8 Jahren

Danke für die Antworten.

Ich lese mir das gerade mal durch.
Sowohl auf msdn als auch Codeproject (link).
Ist aufjedenfall eine interessante Vorgehensweise.
Habt ihr denn vielleicht auch schonmal versucht, solch eine Logik zu extrahieren? Sprich in eine externe Text/Config Datei? Ich fände das äußerst nett. Sowohl während der Programmierung mit anderen Kollegen als auch für weitere Dinge (Bereiche (Schein-)sperren).

Gruß

5.299 Beiträge seit 2008
vor 8 Jahren

ich kann mir nix drunter vorstellen, unter "die Logik in eine Datei extrahieren".
Ich verpass meinen Commands den CanExecute-Delegaten, und dan checken daran gebundene Buttons und MenuItems, ob sie enabled sind oder nicht.
Je nachdem, worauf der CanExecute-Delegate "zeigt", kann das was ganz unterschiedliches sein.

Der frühe Apfel fängt den Wurm.

F
10.010 Beiträge seit 2004
vor 8 Jahren

ähm - wenn man ein RelayCommand nutzt, dann nutzt man grade kein CommandBinding.

Komisch, ich mache es genau andersrum.
Wenn ich RelayCommand benutze dann per Bindung auf Command des Button o.ä.

Wobei ich das über Eine CommandMap mache die ich per Konventionen befülle.
http://blogs.msdn.com/b/morgan/archive/2010/06/24/simplifying-commands-in-mvvm-and-wpf.aspx

U
Unfug Themenstarter:in
133 Beiträge seit 2006
vor 8 Jahren

Danke nochmal.

Die Idee mit der Konfigdatei bezog sich darauf, dass man von "außen" dies steuern könnte ohne den Code extra neu zu kompilieren.
Wie eine klassische Konfig eigentlich, nur halt für die UI. Wahrscheinlich war es einfach zu lange her, dass ich mit WPF was gemacht habe. Ich werde mir diese CommandBinding und RelayCommands näher anschauen.

Sieht ja relativ einfach aus. Vor allendingen diese CommandMap von FZelle sah äußerst interessant aus. So bleibt, meiner Meinung nach, der Code auch recht sauber.

5.299 Beiträge seit 2008
vor 8 Jahren

jo, sieht nützlich aus.

nur noch einmal: "CommandBinding" ist etwas anderes, ist eine eigene Klasse, und ist nochmal anders zu benutzen.

Der frühe Apfel fängt den Wurm.

T
461 Beiträge seit 2013
vor 8 Jahren

CommandMap kannte ich bisher gar nicht, sieht sehr praktisch und effizient aus! Danke!

Habt ihr denn vielleicht auch schonmal versucht, solch eine Logik zu extrahieren? Sprich in eine externe Text/Config Datei?

Meinst du Konfig auslesen und Inhalte im Code anwenden?

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

F
10.010 Beiträge seit 2004
vor 8 Jahren

@ErfinderDesRades:
Schon richtig, aber mit meiner Erweiterung der CommandMap sieht es dann noch einfacher aus.

Im Xaml:


 <mui:ModernButton HorizontalAlignment="Right" VerticalAlignment="Center"
                              IconData="F1 M 35,19L 41,19L 41,35L 57,35L 57,41L 41,41L 41,57L 35,57L 35,41L 19,41L 19,35L 35,35L 35,19 Z" IconHeight="24" IconWidth="24"
                              Style="{DynamicResource CoolButton}"
                              ToolTip="{x:Static p:LocalizedText.Hinzufuegen}" 
                              Command="{Binding Commands.AddLicensesCommand}"/>

Und der Code aus dem MVVM ViewModelsieht dann so aus:


#region AddLicensesCommand
///-------------------------------------------------------------------------------------------------
/// <summary> AddLicensesCommand wird per Binding von CommandMap aufgerufen
///           Binding in XAML wird per Commands.AddLicensesCommand erstellt.</summary>
/// <remarks> xyz, 13.06.2015.</remarks>
public void AddLicensesCommand()
{
	LogVerboseInfo("AddLicensesCommand Called");
}
///-------------------------------------------------------------------------------------------------
/// <summary> Wird von WPF automatisch bei Änderungen im Databinding aufgerufen und 
///           erlaubt ein Enable/Disable des AddLicensesCommand.</summary>
/// <remarks> xyz, 13.06.2015.</remarks>
/// <returns> true AddLicensesCommand kann ausgeführt werden, false wenn nicht.</returns>
public bool CanAddLicensesCommand()
{
	return true;
}
#endregion

Das wars, kein weiterer Code nötig.
Dann noch ein Snippet dazu und die Base MVVM Klassen....

U
Unfug Themenstarter:in
133 Beiträge seit 2006
vor 8 Jahren

Ja genau ThomasE.
Allerdings nur auf die UI bezogen.

Ich habe soetwas schonmal in einer C Anwendung gesehen. Dort gab es eine Konfigurationsdatei in der tatsächlich diese Abhängigkeiten drin standen. Und man konnte es zur Laufzeit ändern. Das ist natürlich schon Jahrzehnte her und ich denke, dass dort irgendeine große Logik mitprogrammiert wurde, so dass das funktioniert.

Da ich viele Dialoge in der Anwendung habe, deren Controls vom Context abgängig (Aktueller Status, was wurde vorher geklickt), wäre sowas natürlich schön zu zentralisieren, damit ich das besser managen kann.

Ich musste leider noch in den letzten Tagen an einer anderen Baustelle arbeiten. Werde aber in 1-2 Wochen mich dann intensiv mit dieser CommandMap mal beschäftigen.

Gruß

F
10.010 Beiträge seit 2004
vor 8 Jahren

Das solltest du nicht tun.

Die CommandMap macht nur Sinn wenn du MVVM verstanden hast und vernünftig anwendest.
Wenn du das aber bereits verstanden hättest, hättest du bereits zustände im VM die Controls Ein/Aus machen oder verbergen.

Beschäftige dich also mit MVVM und vorallem OOP, das macht viel mehr Sinn.

T
461 Beiträge seit 2013
vor 8 Jahren

Ja genau ThomasE.
Allerdings nur auf die UI bezogen.

Ich habe soetwas schonmal in einer C Anwendung gesehen. Dort gab es eine Konfigurationsdatei in der tatsächlich diese Abhängigkeiten drin standen. Und man konnte es zur Laufzeit ändern. Das ist natürlich schon Jahrzehnte her und ich denke, dass dort irgendeine große Logik mitprogrammiert wurde, so dass das funktioniert.

Da ich viele Dialoge in der Anwendung habe, deren Controls vom Context abgängig (Aktueller Status, was wurde vorher geklickt), wäre sowas natürlich schön zu zentralisieren, damit ich das besser managen kann.

Hmm, wie FZelle schon sagte, sich zuerst mal ein wenig in diese Themen einarbeiten.

Denn wenn das geschafft ist, ist der Rest auch nur noch ein Klax.
Dann vertseht sich der Rest von selbst 😉

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

U
Unfug Themenstarter:in
133 Beiträge seit 2006
vor 8 Jahren

Hallo Fzelle,

ja ist richtig.
Ich nutze derzeit kein MVVM mittels bekannter Frameworks, sondern habe eine eigene Implementierung.

UI ist nicht so meine Expertise, jedoch hatte ich festgestellt, dass meine Programmierung sich ähnelt mit den ganzen Frameworks. Ein VM existiert somit, jedoch nicht auf die Art und Weise, dass es für WPF optimiert ist (ICommand).
In der Code Behind Datei sind im Prinzip nur Weiterleitungen und keine BusinessLogik.
Obwohl WPF diese netten Sachen wie DataBinding per XAML erlaubt, muss ich zugeben, dass ich diese ungern nutze. Die Möglichkeit einiges erst zur Laufzeit zu testen schreckt mich manchmal ab.

Die Geschichte mit den Controls wird mich aber dazu führen, dass ich mich damit nochmal (extra für die Windows Variante) beschäftigen muss.

Aufjedenfall vielen Dank für die Tipps und Tricks. Ich werde mich demnächst damit auseinandersetzen. Das ist fest eingeplant.
Ich würde mich natürlich freuen, wenn Du über deine Variante der CommandMap noch mehr schreiben könntest. Möglicherweise hast Du ja schon irgendwo ein Blogeintrag?!

Gruß

Update: ThomasE:
Ja da habt ihr Recht. Werde ich definitiv machen. Manchmal läuft einem einfach nur die Zeit davon 😁

189 Beiträge seit 2014
vor 8 Jahren

Ein VM existiert somit, jedoch nicht auf die Art und Weise, dass es für WPF optimiert ist (ICommand).

Da liegt ja dann der Hase im Pfeffer begraben.

Die Möglichkeit einiges erst zur Laufzeit zu testen schreckt mich manchmal ab.

Also, soweit meine Erfahrung geht, machst du dann was grundlegend falsch.
MVVM erzwingt ja eine ordentliche Trennung UI <-> BL+DAL, gerade damit man gut testen (UnitTests) kann.
Oder reden wir an einander vorbei?

U
Unfug Themenstarter:in
133 Beiträge seit 2006
vor 8 Jahren

Hallo Ezio,
nein Du hast schon recht soweit bzgl. WPF.

Es existiert in meiner Programmierung eine klare strikte Trennung von UI, BL und DAL. Es ist also bisher auch kein Problem die UI direkt auszutauschen oder DAL oder die BL. Alles ist soweit in Ordnung und funktioniert wie es funktionieren muss.

Somit hast Du Recht mit der Aussage "Da liegt ja (...)", da ich aufgrund meiner eigenen Implementierung nicht direkt ICommand genutzt habe. Ich muss zugeben, dass mir das Konzept auch nicht bisher so bekannt war, weil die Ebene UI/WPF von mir Stiefmütterlich bisher behandelt wurde. Bin mehr in der tieferen Ebene Zuhause.

Ich habe jetzt schon bisschen mehr gelesen und ja, es löst sogar das Problem, dass ich gehabt hatte mit den Laufzeitfehlern.
Zum Beispiel: Eine Collection wird nur angebunden, wenn eine Vorbedingung erfüllt ist.

Ich werde definitiv mich jetzt damit auseinander setzen und es einbauen.

Gruß

F
10.010 Beiträge seit 2004
vor 8 Jahren

Du bringst da einiges durcheinander.
ICommand hat erst einmal überhaupt nichts mit MVVM und Databinding zu tun.

Wenn du im Codebehind irgendwelche Weiterleitungen machst, machst du zu 90% kein wirkliches MVVM und hast damit wahrscheinlich auch die Trennung nicht so wirklich vollzogen.

Und MVVM hat erstmal überhaupt nichts mit vorhandenen Frameworks zu tun.

U
Unfug Themenstarter:in
133 Beiträge seit 2006
vor 8 Jahren

Hallo zusammen,

inzwischen bin ich etwas weitergekommen. Ich wollte mal euer Feedback einholen.
Ich werde die Solution anhängen, um darüber zu diskutieren.

Folgender Aufbau:
Klassen

Car [Stellt das Model dar]
CommandMap [ist die CommandMap jedoch abgehändert - dazu gleich mehr]
ViewModel [ist der DataContext für das WPF. Alle Models kommen hier als Variable rein]
MainWindow [WPF]

In der CommandMap gibt es zu der Version von FZelle folgende Änderungen:
Statt predicates werden Func<bool> für canExecute übergeben
Statt ICommands werden DelegateCommands verwendet.

Warum habe ich letzteres gemacht? (Der alte Code steht kommentiert noch drin)
Antwort:



          public event EventHandler CanExecuteChanged
           {
               add { CommandManager.RequerySuggested += value; }
               remove { CommandManager.RequerySuggested -= value; }
           }

Dieser Bereich führt dazu, dass bei jedem Klick, egal wohin, die canExecuteChanged Methode ausgeführt wird. Das ist natürlich absolut unschön, dass ständig etwas gefeuert wird.
In diesem Video von Channel 9 geht der Entwickler genau darauf ein und setzt aus diesem Grund das von Prism umgesetze DelegateCommand ein.
Dies habe ich daher entsprechend auch gemacht. Dadurch wird tatsächlich nur dann das canExecuteChanged ausgeführt, wenn man es auch irgendwo "gefeuert" hat.

Weiterhin habe ich die folgende Methode hinzugefügt:


        public void RaiseCanExecuteChanged(string commandName=null)
        {
            if (commandName == null)
            {
               foreach (DelegateCommand item in Commands.Values)
                {
                    item.RaiseCanExecuteChanged();
                }
                return;
            }
            Commands[commandName].RaiseCanExecuteChanged();
        }

Dies war notwendig, damit ich dann in dem ViewModel auch ein RaiseCanExecuteChanged durchführen kann.
Sollte ich ein konkreten Namen übergeben, so wird auch nur die entsprechende canExecuteChanged Methode für das bestimmte Command gefeuert.

Soweit funktioniert auch alles und entspricht auf UI Ebene meinen Vorstellungen, wann etwas aktivierbar ist und wann nicht.

Jetzt habe ich folgende Fragen:

Wenn ich das so umsetze, dann hätte ich bei vielen Model-Klassen eine Vielzahl an Properties und Instanzen im ViewModel. Weiterhin würde jeder Button, jede Listbox, jedes Control eine Methode in der selben Klasse haben. Ist das korrekt so? Und generell freue ich mich über Diskussionen darüber, ob die Änderungen sinnig sind.

Ich füge die Solution als Zip an.

Gruß

5.299 Beiträge seit 2008
vor 8 Jahren

Wenn ich ein Viewmodel im Xaml instanzieren will, kompilierts nicht mehr

Fehlermeldung:
Error 1 Could not load file or assembly 'Microsoft.Practices.Prism.Mvvm, Version=1.1.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. Das System kann die angegebene Datei nicht finden.

Jetzt hab ich glaub die Dll eingebunden, dafür kriege ich jetzt diesen Fehler:> Fehlermeldung:

Error 6 The type 'Microsoft.Practices.Prism.Commands.DelegateCommand' exists in both 'C:\Users\Account2\Downloads\WpfApplication3\WpfApplication3\packages\Prism.4.1.0.0\lib\NET40\Microsoft.Practices.Prism.dll' and 'C:\Users\Account2\Downloads\WpfApplication3\WpfApplication3\packages\Prism.Mvvm.1.1.1\lib\net45\Microsoft.Practices.Prism.Mvvm.dll'

Ist Prism wirklich so dolle, wenn denen scheinbar unterläuft, dass in 2 Libs dieselben Klassen vorkommen?

Naja, vmtl. komme ich mit der richtigen Einbinderei nicht klar, kann vlt. mir jmd helfen?

Der frühe Apfel fängt den Wurm.

U
Unfug Themenstarter:in
133 Beiträge seit 2006
vor 8 Jahren

Aber ohne die Änderungen klappt es? Ich hatte das DataContext = new ViewModel in den CodeBehind gepackt, weil bei mir sonst der Designer rumgesponnen hat.

Update: was ist eigentlich C:\Users\Account2\Downloads\WpfApplication3\WpfApplication3\packages\Prism
.4.1.0.0\lib\NET40\Microsoft.Practices.Prism.dll'?

Die habe ich gar nicht eingebunden. Nur die MVVM

5.299 Beiträge seit 2008
vor 8 Jahren

Ah - ok, den Verweis kannman rausschmeissen.

Also es ist ziemlich entscheidend, Viewmodels im Xaml zu notieren, nicht im Codebehind.
Weil wenns im Xaml notiert ist, hilft dir das PropertyGrid beim richtigen Setzen von Bindings.

Ja, und nu spinnt er im Xaml-Designer mit > Fehlermeldung:

Error 1 Could not load file or assembly 'Microsoft.Practices.Prism.Mvvm, Version=1.1.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. Das System kann die angegebene Datei nicht finden. ich weiß halt nicht, wo er die Datei sucht - was bei den Verweisen angegeben ist als Pfad stimmt jedenfalls, und im Debug\Bin ist eine Kopie auch vorhanden.

Ich lege ja immer ziemlich wert darauf, dass so Zeugs auch funktioniert, grade für Anfänger ists doch reines Gift, wenn sie mit halblebigen Tools herumkrepeln müssen. So lernst du ja nie, wie's eigentlich gedacht ist, Bindings zu setzen.

Der frühe Apfel fängt den Wurm.

U
Unfug Themenstarter:in
133 Beiträge seit 2006
vor 8 Jahren

Interessant.
Bei mir kommt nur Error Object reference not set to an instance of an object.

Und der Designer wird dann nicht angezeigt. Deine Meldung kriege ich aber nicht.

   <Window.DataContext>
        <vm:ViewModel></vm:ViewModel>
    </Window.DataContext>