Mmmh, die Idee war eigentlich, dass automatisch nach der Sensorhardware gesucht wird und nix eingestellt werden muss. Im Fall der o.g. seriellen Ports eine feste Baudrate, etc. und im Falle eines Wechsel auf direkte USB-Kommunikation gibt's wahrscheinlich auch nix einzustellen.
Ich hab mich dabei auf dein Kommentar bezogen:
Zitat von Locutus
Von der GUI zur Logikschicht, also bspw. für die Einstellungen der Sensoren, hier bin ich unschlüssig, wie das aussehen soll
Zitat von Locutus
Ich hab eine eigene Klasse für den COM-Port definiert. Hier gibt's ein privates Serialport-Objekt, welches bei Instanzierung nach der Hardware sucht. Öffentlich mache ich nur die o.g. Funktionen über das Interface. Meinst du das mit auslagern und kapseln?
Jap genau das meinte ich... nur nochmals wiederholt um die Wichtigkeit hervorzuheben :)
Zitat von Locutus
Das hatte ich vergessen zu erwähnen, ich bin "klassisch" mit WinForms unterwegs. Ich sehe keine Vorzüge in WPF (wobei ich mich mit tieferen Infos dazu auch nicht weiter beschäftigt habe). Da VS wohl keinen Editor dafür hat und man dafür auch noch XML(?) an der Backe hat, um die GUI zu definieren, war das für mich nicht interessant.
Ich habe auch mit WinForms angefangen und sehe seit WPF keinen Grund mehr das Zeugs jemals wieder anzugreifen :)
Es ist sicherlich eine Umstellung aber man arbeitet sich glaub ich da schnell ein da es mMn. wesentlich intuitiver ist als WinForms.
Ein Qualitätskriterium für mich ist wie testbar Code ist (weswegen ich ständig vom Testen rede) - ich arbeite nicht immer (eher selten) nach TDD-Regeln aber zumindest schau ich dass ich alles soweit entkopple, dass jeder entscheidende Code-Pfad ohne Nebeneffekte getestet werden kann. Das begingt wie schon mehrmals erwähnt beim Auslagern von Code in eigene Klassen, weiter noch die Abhängigkeiten der Klassen untereinander durch Interfaces definieren, sodass am Ende jede Klasse beispielsweise nur mit "Fake-Instanzen" getestet werden kann.
das ist schon mal ein guter Ansatz den du da vorgeschlagen hast und einiges bei der Implementierung ist mMn. wirklich Geschmackssache und solche Vorgehensmodelle sollen dabei helfen die Komplexität zu reduzieren sowie Test- und Wartbarkeit verbessern.
Ich würde auch so Anfangen die externen Resourcen zu kapseln. Die verschiedenen Hardware-Schnittstellen zB. durch ein gemeinsames Interface kann für gewisse Consumer im Code Sinn machen um einheitlich mit den Schnittstellen zu kommunizieren aber speziell die Konfiguration der unterschiedlichen Hardware-Schnittstellen wird sich mit einem allgemeinem Interace nicht abbilden lassen und somit wird man vermutlich Richtung GUI konkretere Interfaces pro Hardware-Schnittstelle brauchen.
Mal abgesehen von den Interfaces die man dafür definiert, der Zugriff sollte ausgelagert und gekapselt sein, was das Testen dieser Schnittstellen erst ermöglicht.
Eine Logik-Klasse kann wahlweise entweder alle Schnittstellen kennen und bedienen oder noch einmal separat pro Schnittstelle existieren - und vlt. noch eine Logik-Klasse darüber haben die diese wieder vereint... Auch wieder aus dem selben Aspekt der Test-und Wartbarkeit. Wenn die Logik sich pro Hardware-Schnittstelle gravierend unterscheidet würd ich teilen, ansonsten reichts wsl. in einer.
Die Logic-Klasse kann wie du vorgeschlagen hast per Calls und Events mit den Hardware-Schnittstellen-Klassen kommunizieren und selbst seine Zugriffe auch wieder durch Funktionen und Events öffentlich machen.
Richtung GUI (angenommen du verwendest WPF) hast du dann ein ViewModel pro View die du darstellen willst, welche die notwendigen Properties (für die View) im Sinne von MVVM an die Gui-Elemente bindet. Die ViewModels sind dann für die Interaktion mit den Logics verantwortlich.
Dein Beispiel mit GetPorts(): Das ViewModel ruft zB. bei der Initialisierung (oder auf Abruf per ICommand von der View getriggert) die Funktion der Logic.GetPorts() auf und setzt das Result einem "Port[] Ports{get;set;}" Property, welches durch INotifyPropertyChanged die GUI benachrichtig, dass diese sich aktualisieren und neue Werte darstellen soll.
Das ViewModel hat quasi die Aufgabe, die Logics für die View besser konsumierbar zu machen.
Auch in den Views und ViewModels: Wenn du die Hardware-Schnittstellen per View Konfigurieren willst, brauchst du wsl. spezifische Views pro Hardware-Schnittstelle (da wsl. unterschiedliche Parameter konfiguriert werden) und dazu spezifische ViewModels, welche diese dann den Logics order Hardware-Schnittstellen-Klassen weiterleiten können.
Da du durch das Auslagern des Codes in verschiedene Komponenten wsl. viele Klassen inkl. Interfaces erzeugen wirst empfiehlt sich Dependency Injection einzusetzen um die Abhängigkeiten zu reduzieren, das Kompositionieren der Services zu vereinfachen und vor allem um den Code testbarer zu machen.
DataContext kann nur ein Objekt zugewiesen werden. Normalerweise hat das Fenster ein MainViewModel, und die einzelnen Unterbereiche im Fenster dann spezielle Unter-ViewModels, welche als Eigenschaften im MainViewModel liegen. Das kann beliebig verschachtelt werden.
Nach dem Schema würde ich auch vorgehen und du könntest es dann zB so schachteln:
und die entsprechenden ViewModels stark vereinfacht:
public class MainViewModel
{
public SprachViewModel SprachViewModel { get; set; } = new SprachViewModel();
public DatenbankViewModel DatenbankViewModel { get; set; } = new DatenbankViewModel();
public FunktionsViewModel FunktionsViewModel { get; set; } = new FunktionsViewModel();
}
public class SprachViewModel
{
public List<string> Sprachen { get; set; } = new List<string> {"Deutsch", "Englisch"};
}
public class DatenbankViewModel
{
public List<string> Datenbanken { get; set; } = new List<string> {"DbA", "DbB"};
}
public class FunktionsViewModel
{
public List<string> Funktionen { get; set; } = new List<string> {"DoSomething", "DoSomethingElse"};
}
ein Kollege in der FH hat im Rahmen seiner Bac-Arbeit eine Umfrage gestartet und gebeten, diese auch an andere weiterzuleiten. Sind 21 Fragen die vielleicht etwas klarer formuliert sein könnten aber trotzdem wärs nett, wenn sich der eine oder andere dafür opfert: Hier gehts zur Umfrage
Ich kanns nicht erklären warum "Path=." den Wert nicht mehr zurückschreibt aber es ist nunmal so: Man kann nur die Eigenschaften des Context verändern, nicht aber den Context selbst.
public partial class MainWindow : Window
{
private string _textProp1;
private string _textProp2;
public MainWindow()
{
InitializeComponent();
DataContext = this;
TextProp1 = "Text1";
TextProp2 = "Text2";
}
public string TextProp1
{
get { return _textProp1; }
set { _textProp1 = value; }
}
public string TextProp2
{
get { return _textProp2; }
set { _textProp2 = value; }
}
}
TextBox1.Text ist an DataContext.TextProp1 gebunden
TextBox2.Text ist an DataContext gebunden, welcher selbst auf DataContext.TextProp2 geändert wurde.
Wenn du nun einen Breakpoint bei beiden Settern setzt, siehst du das (1) verändert wird aber (2) nicht.
Lg, XXX
//Edit: Um meinen vorigen Vorschlag nochmal zu verdeutlichen: Deine Items in der Listbox müssen in einem Wrapper-Objekt sein, damit du eine Property hast die du verändern kannst. Du kannst nicht den Kontext selbst ändern aber die Eigenschaften sehrwohl.
wie hast du denn das SQL der Statements extrahiert? Per SQL-Profiler? Falls nicht würde ich das nochmal probieren: Die komplette Abfrage (nicht nur die einzelnen separiert) im Profiler loggen lassen und dann gemeinsam im SSMS ausführen lassen um zu sehen obs dort funktioniert.
Weiters kann es sein (und hatte ich schonmal), dass Sachen im SSMS funktionieren, die aber im PGM nicht funktionierten. Ich kann mich nur mehr grob daran erinnern, dass "SET ARITHABORT OFF/ON" da teilweise geholfen hat bzw. kann es auch Probleme mit dem Ausführungsplänen im SQL Server geben. Evt. mal die irgendwo resetten probieren.
Wie schauts aus, wenn du das Timeout anhebst? Wird die anfrage dann fertig oder nicht?
1) Du hast eine ListBox in der die "ausgewählten Produkte" dargestellt werden
2) Irgendwo (extern) fügst du dann ein neues "Produkt" deiner Liste hinzu, welches vermutlich am Anfang leer sein wird.
3) Jeder Eintrag in der ListBox wird durch eine ComboBox dargestellt, welche selbst widerum alle Produkte zur Auswahl hat.
4) Dadurch kann man dann in der Liste der ausgewählten Produkte diese noch verändern, was sich klarerweise auch in der Liste der ausgewählten Produkte widerspiegeln soll.
5) (später soll neben jedem Item in der Liste noch ein Button zum Entfernen hinzukommen)
Ich vermute mal das das Problem bei der Art des Bindings des SelectedItems zu suchen ist.
- Mein erster Versuch wäre, die ListBox-Produkte in eine Wrapper-Klasse "ObservableList<SelectedProduct>" zu stecken. SelectedProduct ist in dem Fall ein ViewModel, welches das Binding erleichtern soll und selbst nur ein Property "Product" (inkl. NotifyPropertyChanged) hat.
- Das Binding auf SelectedItem würde dann nicht auf "Path=." sondern "Path=Product" in SelectedProduct schauen und jede Manipulation würde dann wieder ordentlich in alle Richtungen durchschlagen.
- kommt der Freeze immer zur selben Zeit/bei der selben Aktion?
- kannst du das Verhalten beim Debuggen auch nachvollziehen?
- wenn die App gerade eingefroren ist, sieht man dann im TaskManager ungewöhnliche CPU-Last und/oder Festplattennutzung?
laut Combobox filter text lost when I type the latest inputs with some delay ist dieses Verhalten hard-coded und nicht veränderbar, jedoch hängt es direkt zusammen mit der Doppel-klick Gewschwindigkeit die man in Windows einstellen kann. Habs gerade getestet und es stimmt. Leider hat man aber hier auch nicht sehr viel Spielraum aber vielleicht hilfts ja schon.
Wesentliche Änderungen:
- DataTrigger.ExitActions definiert
- Bei der Vergrößern Animation noch ein "from" eingebaut, da beim Reset des vorigen Triggers die Breite wieder den Ursprungswert von 230 hat und somit nichts mehr zu tun ist.
wenn dein Matrixcontrol nur ein Layout-Container sein soll, dann wärs schöner, wenn er sich nur ums Layout kümmert. Die Visuelle Darstellung würde ich dann entweder per DataTemplates ganz ausserhalb oder in einer Zwischenschicht realisieren.
Darüber ein MatrixControl, welches dann aus einem ItemsControl mit MatrixLayout als ItemsPanelTemplate verwendet sowie aus einem custom ItemTemplate besteht. Passend dazu brauchst du dann natürlich attached Properties (wie Grid.Row) um den Child-Elementen die richtige Zeile/Spalte zuzuweisen (oder halt irgendwie automatisch setzen), welche dann vom MatrixLayout verwendet wird um die richtigen Controls zu platzieren.
- Die System.Windows.Interactivity.dll mal aus dem Zielverzeichnis löschen und schauen ob das Service noch immer läuft.
- Eventuell benötigt eine verwendete Bibliothek diese quasi indirekt?
- Wenn du das Zielverzeichnis cleanst und nur Service-Relevante Projekte kompilierst, wird die System.Windows.Interactivity.dll dann auch rein kopiert?
- Wenn es sich garnicht beheben lässt, könntest du CopyLocal deaktivieren und das File manuell per PostBuild Script ins Zielverzeichnis kopieren (nur wenn unterschiedlich)
Wie wärs mit einem Singleton der ThreadLocal im Hintergrund verwendet? ThreadLocal hat ja die Eigenschaft IsValueCreated, mit der du im Singleton dann prüfen könntest, ob es sich um einen neuen Thread handlet und ihn gleich dort initialisieren.
Das wird es wohl sein. Ein Style-Setter kann keine manuell gesetzten Properties überschreiben. Wenn du aus irgendeinem Grund ein Property vom Start weg setzen willst, mach dies ebenfalls im Style per Setter.
Wenn mehrere benutzer auf die gleichen Daten zugreifen, musst du die Daten entweder vorher sperren, oder sie mit einem Timestamp versehen und vor dem Update prüfen ob sie sich verändert haben und entsprechend darauf reagieren.
anstatt beim Checked Event den String zu erweitern, würde ich den Inhalt der Textbox bei _jeder_ Änderung komplett generieren lassen. (Anhand der ausgewählten Optionen)
Die Textbox selbst darf dann natürlich nicht mehr editierbar sein und etwaige zusatzeingaben müssen über entsprechende Formularfelder (bei den Checkboxen) eingetragen werden.
Dies hat zur Folge, dass ganz unabhängig ob etwas an- oder abgehackt wird, immer der richtige Command erzeugt wird.
Lg, XXX
//Edit: Ja prinzipiell eh das selbe was Coffeebean gesagt hat... :P
@Th69: weil er als Value im Property nur eine Art ID hat und dafür aber einen anderen Wert anzeigen lassen will.
@rokohl: Du kannst einem Binding einen Converter vom Typ IValueConverter oder IMultiValueConverter übergeben, der dann die Konvertierung für dich vornimmt.
es gilt nach wie vor: Wenn du nicht ordentlich erklärst was du überhaupt erreichen willst, kann dir hier auch niemand helfen.
Du postest einen Codeauschnitt mit einem DockingPanel und einem TabControl als Child und erwähnst nicht das du noch andere Controls darin platzieren willst. Welche, Wieviel und Wohin sollen die denn kommen? Das können wir nicht erraten.
Der Einwand von Lando ist gerechtfertigt: Solange du Width gesetzt hast, wird dein TabControl sich nicht in der Breite automatisch anpassen können.
Den Begriff "Anchor" gibt es im WPF meines Wissens nach nicht mehr. Was stattdessen eben verwendet wird sind automatische (also nicht gesetzte) Breiten & Höhen inkl. passenden Margins und/oder Paddings.
vielleicht erklärst du noch ein wenig, was du eigentlich vor hast. Wieso willst du, dass Width & Height gesetzt ist, wenn du dann eh nur die Breite und Höhe des Parents übernimmst?
Du kannst auf jeden Fall immer die aktuelle Breite und Höhe mit den Properties ActualWidth und ActualHeight auslesen. Das Setzen der eigentlichen Breite und Höhe sollte man eigentlich vermeiden und mit LayoutContainern arbeiten außer es gibt spezielle Gründe dafür.
Lg, XXX
PS: ActualWidth und ActualHeight werden auch beim Maximieren gesetzt.
also eine rudimentäre Lösung zu Problem 1 wäre ein Script in den Autostart Folder zu legen das sich selbst nach dem ersten run löscht. In dem Script kannst du dann die restlichen Aufräumarbeiten erledigen die ersten nach dem ersten Login anfallen.