Hö? Was machst du? Du brauchst nur ein Grid. Und warum ist da immer noch md und sm?
Hallo Bronstein
Du hast die Breite so konfiguriert: md="4"; mach das mal weg.
Gruss
Alf
Hallo pollito
Es gibt fertige Komponenten zu kaufen, die das können.
Alternativ in Pdf oder Html konvertieren und anzeigen.
Gruss
Alf
Hallo joerg55
Das ist nicht ohne weiteres möglich.
Man kann zwar CheckedListBox überschreiben:
public class CheckedListBoxWithCustomHeight : CheckedListBox
{
private int itemHeight = 40;
[Browsable(true)]
[Category("Behavior")]
public override int ItemHeight { get => this.itemHeight; set => this.itemHeight = value; }
}
Aber die Schrift selbst wird nicht verschoben.
Schwer zu sagen, ohne den relevanten Code zu kennen.
Grundsätzlich werden die Daten ins ViewModel geladen und nicht direkt auf der View geändert. Das ViewModel hat ICommand-Properties, die an die Buttons in der View gebunden sind (https://www.c-sharpcorner.com/UploadFile/851045/command-design-pattern-in-C-Sharp/).
Wird der Command ausgelöst, wird eine Methode im ViewModel ausgeführt, die die Daten lädt. Mit CommunityToolkit.Mvvm wird die entsprechende Methode einfach mit [RelayCommand] attributiert. Das Command-Property wird generiert und nicht händisch implementiert.
Das ViewModel informiert dann die View über das INotifyPropertyChanged-Event. Mit CommunityToolkit wird das Property mit [ObservableProperty] attributiert, anstatt das NotifyPropertyChanged-Event händisch auszulösen.
Beispiel:
internal partial class MainViewModel : ObservableRecipient
{
[ObservableProperty]
private ObservableCollection<string>? data;
[RelayCommand]
void LoadData()
{
Data = new ObservableCollection<string>
{
"Data A",
"Data B",
"Data C"
};
}
}
<StackPanel>
<ListView ItemsSource="{Binding Data}" />
<Button Content="Load Data" Command="{Binding LoadDataCommand}" />
</StackPanel>
Benutzt du denn ein ViewModel pro Page oder eines für alle?
Möglicherweise der Virenscanner auf dem anderen Rechner.
Weil es hier noch keine Antwort gibt:
Wenn die Daten programatisch geändert werden, soll das nicht im DataGrid gemacht werden, sondern an dem gebunden Property. Das muss natürlich entsprechend mit INotifyPropertyChanged ausgestattet sein.
Hallo TomSchmitz
Ich glaube nicht dass es eine Library gibt, die das Verschmelzen automatisch macht.
Wirst also mit der passenden Library Header und Footer auslesen und neues Pdf generieren müssen.
Über die Forensuche findest du die Libraries, die du verwenden kannst.
Gruss
Alf
Hallo Timm
CanExecute kann also true, false und Null sein.
CanExecure ist eine Art Methode, die true oder false zurück gibt. Kann bei deiner ICommand-Implementierung aber auch null sein, dann wird also keine Methode übergeben und CanExecute gibt dann immer true zurück.
<Button x:Name="btn_speichern" Content="Datensatz speichern" HorizontalAlignment="Left" Margin="25,350,0,0" VerticalAlignment="Top" Height="48" Width="150" /> <DataGrid x:Name="DataGrid1" Margin="25,100,25,100" AlternatingRowBackground="Aqua" AutoGenerateColumns="false" VerticalGridLinesBrush="#FFF8F4F4" HorizontalGridLinesBrush="#FFFAF7F7"> ... </DataGrid> ... <Button x:Name="Btn_OK" Content="OK" HorizontalAlignment="Left" Margin="325,65,0,0" VerticalAlignment="Top" RenderTransformOrigin="-0.1,-0.564" Width="124" />
Im Xaml-Code fehlen die Bindings. Beim Button das Command-Binding und beim DataGrid das ItemsSource-Binding.
// Deine Verson mit new (); ist erst ab Sprachversion C#9 oder höher verfügbar // Ich nutze die Community Version Visual Studio 2022; keine ausstehenden Updates; ist die Sprachversion bei mir verfügbar?
Die C#-Version hängt mit der .NET-Version zusammen, die im Projekt eingestellt ist.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version
//Button wurde gedrückt DelegateCommand wird ausgeführt; Warum muss ein neues Object vm erzeugt werden??? this.LoadCommand = new DelegateCommand((vm) => LoadData(vm));
'vm' ist in diesem Fall das ViewModel, dass vom Command (per CommandParameter-Binding) übergeben wird. Es wird also kein neues Objekt erzeugt.
Das beantwortet auch die Frage:
//Welche Daten soll das object boxedMainViewModel aufnehmen
private void LoadAllMitarbeiter() { this.AllMitarbeiter.Clear(); foreach (var mitarbeiter in this.mitarbeiterService.GetAll()) { this.AllMitarbeiter.Add(mitarbeiter); } } //Den Part verstehe ich nicht, wozu dient der Mitarbeiterservice? public MitarbeiterOverviewViewModel(MitarbeiterService mitarbeiterService) { this.mitarbeiterService = mitarbeiterService;
Der MitarbeiterService stellt die Verbindung zur Geschäftslogik her, von dort kommen die Mitarbeiter-Daten und da gehen sie wieder hin, wenn sie gespeichert werden sollen. Alles was mit Datenbank zu tun hat, wird dahinter versteckt und hat in der UI nichts mehr zu suchen.
Schau dir dafür das hier an: https://mycsharp.de/forum/threads/111860/artikel-drei-schichten-architektur
SqlConnection connection = new SqlConnection("Data Source=....;initial Catalog = Company_Test;Integrated Security=True"); connection.Open(); /// Die Datenbankverbindung stelle ich zukünftig über die neue Klasse ADO.Net Entity Data Model her??? Aber warum brauche ich dann noch die /// SQL connection???
Kein Plan wo die Daten aktuell herkommen. Für die UI ist das auch nicht wichtig. Wie ich schon geschrieben hatte, muss der Datenbank-Kram aus der UI raus und hinter den MitarbeiterService.
Mein MainWindow (Model) sieht zurzeit wie folgt aus:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } }
Wo wird das ViewModel dem DataSource vom Window zugewiesen?
Nach meinem derzeitigen Verständnis wird das Button-Click Event durch ein Command-Binding ersetzt. check
Dazu wird der OK-Button per Datenbindung mit dem ViewModel verbunden. check
Das ViewModel enthält die Logik, was mit dem View passieren soll wenn z.B. ein Button geklickt wird, eine Änderung etc. erfolgt. checkWird nun der OK-Button geklickt erzeugt es einen neuen DelegateCommand, dieser wiederum ruft die Methode LoadData auf usw..
Der DelegateCommand wird schon im Konstuktor vom ViewModel erzeugt und enthält eine Verknüpfung auf die LoadData-Methode.
Ich hoffe, dass es bis hierhin richtig verstanden und wiedergegeben habe. Ich glaube es wäre für mich sehr hilfreich wenn wir Schritt für Schritt vorgehen.
Ich habe die letzten Tage soviel gelesen, dass ich den Wald vor lauter Bäume nicht mehr sehe.
Es wäre ja langweilig, wenn es einfach wäre. 😃
Hallo Timm
Das MainViewModel braucht noch ein Property für die Mitarbeiter-Liste:
public ObservableCollection<MitarbeiterViewModel> AllMitarbeiter { get; } = new();
Im View wird das DataGrid daran gebunden:
<DataGrid ItemsSource="{Binding AllMitarbeiter}" />
Ausserdem wird der Load-Button an den DelegateCommand gebunden:
<Button Content="Load Mitarbeiter" Command="{Binding LoadCommand}" CommandParameter="{Binding}" />
Der CommandParameter ist der DataContext, also das MainViewModel.
Des Weiteren weiß ich nicht wie ich den Konstruktor des DelegateCommand füllen muss, damit dieser dann das Auslesen aus der Datenbank durchführt.
Der execute-Parameter beim DelegateCommand ist die Methode, die beim Button-Click ausgeführt wird.
public MainViewModel()
{
// Load_data → LoadCommand
this.LoadCommand = new DelegateCommand((vm) => LoadData(vm));
}
...
private void LoadData(object boxedMainViewModel)
{
var mainViewModel = boxedMainViewModel as MainViewModel;
mainViewModel.LoadAllMitarbeiter();
}
...
private void LoadAllMitarbeiter()
{
this.AllMitarbeiter.Clear();
foreach (var mitarbeiter in this.mitarbeiterService.GetAll())
{
this.AllMitarbeiter.Add(mitarbeiter);
}
}
In this.mitarbeiterService.GetAll()
werden die Daten aus der Datenbank geladen.
Zum Testen reicht da auch sowas:
internal IEnumerable<Mitarbeiter> GetAll()
{
yield return new Mitarbeiter("Guybrush", "Threepwood", "Monkey Island");
yield return new Mitarbeiter("Elaine", "Marley", "Melee Island");
}
Beim DelegateCommand ist mir nicht klar warum als parameter "null" übermittelt wird. Nach meinem Verständnis kann ein Button doch nur geklickt also True oder nicht geklickt False liefern.
Der canExecute-Parameter zeigt nicht an, ob der Button gedrückt wurde, sondern ob er gedrückt werden darf. Wenn nein, dann wird er in der UI deaktiviert angezeigt. Den kannst du erstmal ignorieren.
Auch ist mir nicht ganz klar, wo der nachfolgende Programmcode hingehört:
SqlConnection connection = new SqlConnection("Data Source=TIMM\\TESTSQL;initial Catalog = Company_Test;Integrated Security=True");
connection.Open();
In den MitarbeiterService, bzw. noch besser in das MitarbeiterRepository, dass vom MitarbeiterService benutzt wird (https://dotnettutorials.net/lesson/repository-design-pattern-csharp/).
Der Rest kann weg.
Habe mir anscheinend ein komplexes Thema ausgesucht, für meine ersten Gehversuche im Bereich MVVM Pattern.
Ja, der Einstieg ist nicht ganz einfach. Die Mühe lohnt sich aber, zum einen für stabilere Programme, zum anderen entwickelt es das eigene Programmier-Verständnis ungemein.
Gruss
Alf
PS: Es folgt noch ein zweiter Beitrag mit ein paar Anmerkungen.
Ja, diese Anforderung wird mit MVVM quasi miterledigt.
Es gibt mehrere Möglichkeiten das zu machen. Hier mal ein ganz einfaches Beispiel:
<ListView ItemsSource="{Binding AllMitarbeiter}">
<ListView.ItemTemplate>
<DataTemplate DataType="local:Mitarbeiter">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Vorname}" Width="100" />
<TextBlock Text="{Binding Nachname}" Width="100" />
<TextBlock Text="{Binding Geburtsort}" Width="100" />
<Button Content="Details" Width="60" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Hallo CSharpNewbie2022
Wie du schon richtig erkannt hast, ist es wichtig, Daten und UI voneinander zu trennen. Bei WPF gibt es dafür das MVVM-Pattern.
https://mycsharp.de/forum/threads/118261/artikel-mvvm-und-databinding
Ausserdem empfehle ich dir noch diesen Artikel:
https://mycsharp.de/forum/threads/111860/artikel-drei-schichten-architektur
Gruss
Alf
Guten Morgen
Ich nehme mal an, dass auf Knopfdruck gespeichert werden soll.
Statt dem ClickEvent kannst du das Command-Pattern verwenden.
Dafür bindest du ein Command an dein ViewModel:
<Button Content="Mitarbeiter speichern" Command="{Binding SaveCommand}" CommandParameter="{Binding AllMitarbeiter}" />
public RelayCommand<ObservableCollection<MitarbeiterViewModel>> SaveCommand { get; private set; }
Im Konstruktor vom ViewModel kann der Command instantiiert werden:
public MitarbeiterOverviewViewModel(MitarbeiterService mitarbeiterService)
{
this.mitarbeiterService = mitarbeiterService;
SaveCommand = new RelayCommand<ObservableCollection<MitarbeiterViewModel>>(SaveAll, CanSaveAll);
}
Eine Implementierung für RelayCommand gibt es hier: https://www.c-sharpcorner.com/UploadFile/20c06b/icommand-and-relaycommand-in-wpf/
Die Methode SaveAll, die vom Command aufgerufen wird, bekommt als Parameter die Liste mit den Mitarbeitern.
private void SaveAll(ObservableCollection<MitarbeiterViewModel>? allMitarbeiterViewModel)
{
if (allMitarbeiterViewModel == null) return;
var allMitarbeiter = allMitarbeiterViewModel.Select(ToMitarbeiter);
mitarbeiterService.SaveAll(allMitarbeiter);
}
Beachte hier, dass ich in meinem Beispiel-Projekt nicht das Model Mitarbeiter direkt im UI verwende, sondern ein MitarbeiterViewModel. Beim Landen und Speichern wird jeweils übersetzt. (Beachte, dass deine ViewModels INotifyPropertyChanged implementieren.)
private Mitarbeiter ToMitarbeiter(MitarbeiterViewModel viewModel)
{
return new Mitarbeiter(viewModel.Vorname, viewModel.Nachname, viewModel.Geburtsort);
}
Der MitarbeiterService hält ein MitarbeiterRepository, über das die Kommunikation mit der Datenbank stattfindet.
Statt über den MitarbeiterService kann das MitarbeiterRepository auch direkt im ViewModel verwendet werden.
Wichtig ist, dass ab hier die UI von der Datenbank und Logik-Schicht getrennt ist: https://mycsharp.de/forum/threads/111860/artikel-drei-schichten-architektur
Den UI-Kram kannst du schonmal ausprobieren. Ziel ist, dass auf Knopfdruck SaveAll mit deinen Mitarbeitern aufgerufen wird. Meine Implementierung im MitarbeiterService:
internal void SaveAll(IEnumerable<Mitarbeiter> allMitarbeiter)
{
foreach (var mitarbeiter in allMitarbeiter)
Debug.WriteLine(mitarbeiter);
}
Wenn das funktioniert, kann das Repository implementiert werden. Bei konkreten Fragen meldest du dich wieder hier.
Gruss
Alf
Hallo Timm2023
Bei WPF benutzt du am besten das MVVM-Pattern:
https://mycsharp.de/forum/threads/118261/artikel-mvvm-und-databinding
DataSet und DataTable brauchst du gar nicht.
Für die Mitarbeiter aus der Datenbank machst du dir in dein ViewModel eine ObservableCollection:
public ObservableCollection<Mitarbeiter> AllMitarbeiter { get; set; }
Im View kannst du daran binden:
<DataGrid DockPanel.Dock="Top" ItemsSource="{Binding AllMitarbeiter}" />
Les dich ein und fang damit an. Damit solltest du soweit kommen, dass die Mitarbeiter angezeigt werden. Für das Speichern kommst du dann mit deinem neuen MVVM-Ansatz wieder.
Gruss
Alf
Mit einem DataTemplate. Hier ist das ganz gut erklärt: https://wpf-tutorial.com/listview-control/listview-data-binding-item-template/
Hallo holzhaus2022
MVVM und Datenbinding ist auf jeden Fall der elegantere Weg 😛
Wenn dich die Ladezeit stört, kannst du ja erstmal ein paar Daten laden und dann den Rest nachladen.
Es ist ausserdem fraglich ob jemand in einer Listbox zig-tausende Einträge haben will.
Unter dem Stichwort Paging findest du eventuell was passendes.
Gruss
Alf
Hallo perlfred
Die "Byte Order Mark" ist nicht Teil der Daten. Sie wird Dateien vorangestellt um die Byte-Reihenfolge im Dokument anzuzeigen. Siehe Wikipedia: https://de.wikipedia.org/wiki/Byte_Order_Mark
Das BOM wird also von File.ReadLines korrekterweise nicht mit zurückgegeben.
Gruss
Alf
PS:
Es wird UTF-8 nicht empfohle das BOM zu benutzen, kommt aber trotzdem vor:
https://stackoverflow.com/questions/2223882/whats-the-difference-between-utf-8-and-utf-8-with-bom/2223926#2223926)
Hallo leuveg
Ich schlage vor, dass du die Gelegenheit nutzt und dich gleich noch in ein paar Themen einarbeitest:
Implementiere die Logik unabhängig von der UI:
https://mycsharp.de/forum/threads/111860/artikel-drei-schichten-architektur
Welche UI du dann verwendest, kannst du dann entscheiden. Versuchs doch mal mit WPF und MVVM:
https://mycsharp.de/forum/threads/118261/artikel-mvvm-und-databinding
Die Logik könntest du Test Driven implementieren:
https://www.c-sharpcorner.com/article/test-driven-development-in-c-sharp-net/
Um Pdf-Mergen kannst du eine Library wie https://www.pdfsharp.net/ verwenden.
SQLite ist okay. Die Datenbank-Abfragen sollten nicht direkt in der Logik stattfinde. Verwende dafür ein Pattern wie:
https://www.c-sharpcorner.com/article/factory-method-design-pattern/
oder ein ORM (Object-Relation-Mapper) wie: https://learn.microsoft.com/en-us/ef/.
Gruss
Alf
Die Fehlermeldung sagt etwas anderes. Dein Zertifikat ist nicht vertrauenswürdig. Da kann ich dir aber leider nicht weiterhelfen.
Hast du schonmal "Trusted_Connection= False" probiert?
Edit:
Kleine Tipp: Stell mal dein Visual Studio etc, auf Englisch um. Dann bekommst du englische Fehlermeldungen. Mit denen kann man unter Umständen mehr anfangen.
Zitat von Moma2023
Aktuelle Fehlermeldung: System.ArgumentException: "Keyword not supported: 'trustedconnection'."
Müsste das nicht "Trusted_Connection=True" sein?
Hallo Moma2023
Zitat von Moma2023
- und alle Datenbank-Tabelln enthalten sind
Hier etwas zum Lesen:
https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
Ich weiss nicht, ob das auf diesen Fall passt, wollte aber eine Denkanregung geben.
Gruss
Alf
Dann musst du den Datenbanktyp natürlich auch zum Konvertieren verwenden:
Beispiel:
public class DateTimeConverter : ValueConverter<DateTime, MySqlConnector.MySqlDateTime>
{
public DateTimeConverter() : base(
dateTime => ConvertToDatabaseDateTime(dateTime),
mySqlDateTime => ConvertToApplicationDateTime(mySqlDateTime))
{ }
private static MySqlConnector.MySqlDateTime ConvertToDatabaseDateTime(DateTime dateTime)
{
return new MySqlConnector.MySqlDateTime(dateTime);
}
private static DateTime ConvertToApplicationDateTime(MySqlConnector.MySqlDateTime mySqlDateTime)
{
int year = mySqlDateTime.Year > 0 ? mySqlDateTime.Year : 1;
int month = mySqlDateTime.Month > 0 ? mySqlDateTime.Month : 1;
int day = mySqlDateTime.Day > 0 ? mySqlDateTime.Day : 1;
int hour = mySqlDateTime.Hour;
int minute = mySqlDateTime.Minute;
int second = mySqlDateTime.Second;
int millisecond = mySqlDateTime.Millisecond;
return new DateTime(year, month, day, hour, minute, second, millisecond);
}
}
Hallo pollito
private static DateTime ConvertToApplicationDateTime(DateTime dateTime)
{
if (dateTime == DateTime.MinValue)
{
// Handhabung für "0000-00-00 00:00:00" aus der Datenbank. Wir können hier z. B.
// DateTime.MinValue oder einen anderen Standardwert zurückgeben.
return DateTime.MinValue;
}
return dateTime;
}
DateTime.MinValue ist 01.01.0001 und nicht 00.00.0000.
Ausserdem sollte das Datum aus der Datenbank nicht vom Typ DateTime sein, sondern irgendwas mit DBDate oder so.
Gruss
Alf
Hallo Ralle77
Hier sind zwei Artikel, die du lesen und verstehen solltest. Damit lösen sich deine Probleme quasi von selbst.
https://mycsharp.de/forum/threads/118261/artikel-mvvm-und-databinding
https://mycsharp.de/forum/threads/111860/artikel-drei-schichten-architektur
Da das etwas aufwändig ist nochmal zu den konkreten Problemen für den Anfang:
Wie kann ich das realisieren, so das die Auswahlmöglichkeiten nicht fest sind, sondern sich der Tabelle anpassen ?
Entweder mittels DataBinding: https://learn.microsoft.com/en-us/dotnet/desktop/wpf/data/?view=netdesktop-7.0
Hier wie man das anwendet: https://www.c-sharpcorner.com/article/explain-combo-box-binding-in-mvvm-wpf/
Oder (so macht man das nicht):
<ComboBox x:Name="fahrzeugAuswahl" />
foreach (var fahrzeug in fahrzeuge)
{
this.fahrzeugAuswahl.Items.Add(fahrzeug.Name);
}
Gruss
Alf
Schau dir nochmal den Link an, den du gepostet hast:
https://learn.microsoft.com/de-de/dotnet/api/system.windows.input.key?view=windowsdesktop-7.0
Namespace:
System.Windows.Input
Assembly:
WindowsBase.dll
Du machst bei deinem Projekt eine Referenz auf die Assembly und machst bei deiner Klasse ein using auf den Namespace.
Ist die Referenz auf die WindowsBase eingetragen?
Ich hab mal ein bisschen rumprobiert:
<Style TargetType="iconPacks:PackIconMaterial">
<Style.Triggers>
<DataTrigger Value="True" Binding="{Binding Path=IsChecked,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ToggleButton}}}">
<Setter Property="Foreground" Value="Green" />
</DataTrigger>
<DataTrigger Value="False" Binding="{Binding Path=IsChecked,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ToggleButton}}}">
<Setter Property="Foreground" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>
<iconPacks:
PackIconMaterial
Kind="Glasses"
Foreground="{StaticResource yellow}"
Width="20"/>
Da wird doch die Farbe für das Icon gesetzt. Folglich müsstest du die Foreground-Eigenschaft für PackIconMaterial anpassen.
Vielleicht könntest du bei deinem ToggleButton-Style einen Trigger einbauen, der den Foreground für das PackIcon anpasst, wenn der Foreground vom ToggleButton gesetzt wird. Nur eine Idee, bin grade nicht sonderlich tief drin, in dem Thema.
Hi theSoulT
Ich vermute du musst als Tricker-Target das 'PackIconMaterial' nehmen und nicht den Button.
Gruß
Alf
Zitat von cprogrammer
Wäre das aus deiner Sicht eine Möglichkeit Alf ?
Falls ja, wie müsste man jetzt in der plugin dll vorgehen ?
Es scheint ja um NinjaTrader zu gehen. Dort kommt man mit:
protected override void OnWindowCreated(Window window)
an die einzelnen Fenster. Du könntest schauen, ob du darüber auch an das von dir benötigte Window kommst.
Falls das nicht klappt, könntest du bei dem Hersteller nachfragen. Es gibt da wohl auch ein Forum.
Ansonsten bietet AutoIt auch ein Nuget-Paket an, mit dem du auf die Daten in dem Fenster zugreifen kannst.
Viel Erfolg 😃
Hört sich nicht gut an, was du da vor hast.
Eventuell hilft dir das hier: https://www.autoitscript.com/site/
Kannst ja auch mal beim Ersteller der Applikation nachfragen.
Hallo cprogrammer
Bietet das PluginSystem der Applikation eventuell entsprechende Methoden an?
Werden die Daten denn irgendwo gespeichert? Hast du darauf Zugriff?
Die Daten über den Dialog abzugreifen ist suboptimal.
Gruss
Alf
Hallo Commander82
Erst mal grundsätzlich: du solltest per DataBinding ein ViewModel mit dem Form verbinden. Ein Clear würdest du dann auf dem ViewModel machen und nicht auf den Controls. Stichworte: MVC ( ~WinForms) / MVVM (~WPF) und ausserdem:
https://mycsharp.de/forum/posts/3758346
Zitat von Commander82
public static void ClearAll(Control ctrl) // man muss heutzutage nicht an Buchstaben sparen: → control { foreach (Control tmp in ctrl.Controls) // mach eine eigene Methode in der du Controls als Liste reingibst // geb deinen Variablen aussagekräftige Namen → control statt tmp { if (tmp is Form || tmp is GroupBox) // switch-Statement, statt if/else-Kaskade { ClearAll(tmp); } else if (tmp is TabControl) { foreach (TabPage tp in tmp.Controls) // ClearAll hier rekursiv verwenden // ...
Hier mal ein Beispiel
internal static class ControlExtentions
{
internal static void ClearAll(this Control.ControlCollection controls) // Das 'this' macht diese Methode zu einer Extension-Methode
{
foreach (Control control in controls)
{
ClearControl(control);
}
}
internal static void ClearControl(this Control control)
{
switch (control)
{
case TabControl c: // Hier habe ich 'c' als Variable genommen, weil der Typ direkt obendrüber steht und man
// direkt erkennt, worum es sich handelt. Wäre das nicht der Fall, dann hätte ich 'tabControl' genommen.
c.Controls.ClearAll();
break;
case TabPage c:
c.Controls.ClearAll(); // rekursiver Aufruf
break;
case TextBox c:
c.Clear(); // Clear-Funktion von Controls verwenden, wenn vorhanden
break;
// ...
case null:
default:
// diese Fälle ignorieren
break;
}
}
}
Ich habe das ganze in eine Statische Klasse (names "helper") gesetz und rufe dann das ganze so auf
helper.ClearAll(this);
Ich bin kein Freund von Helper-Klassen. Klassen sollen eine bestimmte Aufgabe haben und das auch durch ihren Namen ausdrücken. Mehr dazu hier:
https://www.c-sharpcorner.com/UploadFile/damubetha/solid-principles-in-C-Sharp/
Spielt jetzt aber keine Rolle, da wir eh eine Extension-Method daraus machen:
würde ja gerne es so machen das ich dies "tihs" Rauslasen kann und er das Formular selbst erkennt von dem der befehl kam .
Das kannst du per Extention-Method machen:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods
Das Ganze hier ist als Anregung zu verstehen und keineswegs als absolute Wahrheit. In der Software-Entwicklung kommt es immer auf die spezifische Situation drauf an.
Viele Grüsse
Alf
Zitat von echdeneth
UserRoles sind bei uns eine Sammlung von Daten die Nutzerspezifisch sind z.B.: FTP Zugänge/PW, Adresse, E-Mail-Zeugs, Lieferantenbesonderheiten usw. welche bei passenden Passwort/Username abgefragt werden können. Keine "UserRoles" um Claim Zusammenhang.
Das Claimdingens passt eigentlich sehr gut zu eurem Szenario. Im von Abt verlinkten Wikipedia-Eintrag ist das ganz gut erklärt.
Das kannst du z.b. mit Active Directory machen. Dann bekommst du dann die meisten Sachen, die du oben angeführt hast umsonst dazu.
Zitat von echdeneth
Demnach Normalisiert und ID (und Namen) abfragen und ne Runde switchcasen...
Ich habe das anders verstanden: Die Enum-Werte als int in der Tabelle speichern und (eventuell mit einer Converter-Klasse) im Programm passend umwandeln.
Zitat von echdeneth
Ob da mehr an Sicherheit reinkommt ist Chefsache...
Der Chef hat davon keine Ahnung. Deswegen ist es unsere Aufgabe als Entwickler ihm das klar zu machen. 😛
Zitat von rockxk
Da ich aber kein C++ Profi bin, komme ich nicht wirklich richtig weiter.
Sei nicht immer so sparsam mit deinen Infos. Woran hapert es denn genau? Was hast du gemacht?
Salut rockxk
Du könntest die Funktionalität in C# implementieren und eine Wrapper-DLL per C++/CLI bereitstellen:
https://learn.microsoft.com/de-de/cpp/dotnet/dotnet-programming-with-cpp-cli-visual-cpp?view=msvc-170
Gruss
Alf
[HttpGet] //public IEnumerable<VIEW_SWP_CYCLETIME> Get([FromForm] VIEW_SWP_CYCLETIME value) public IEnumerable<VIEW_SWP_CYCLETIME> Get(int lineID, int machineID) { return _currentRepository.Data.Where(item => (machineID > 0 || item.MACHINE_ID == machineID) && (lineID > 0 || item.LINE_ID == lineID) ); }
Hallo Bronstein
Wofür ist denn 'machineID > 0' und warum ist das 'verodert'?
Gruss
Alf
Zitat von perlfred
Im Prinziep möchte ich, dass Als erstes data1 abgerufen wird, danach data2 oder data3 und am Schluß Vorgang1 ausgeführt wird.
Task hat doch sowas wie .ContinueWith(). Schau dir das mal an.
Hallo cprogrammer
Zitat von cprogrammer
//Unklar var positive = deltaInfos.Where(h => h.Delta > 0).Average(h => h.Delta); var negative = deltaInfos.Where(h => h.Delta < 0).Average(h => h.Delta); var ControlPositive = deltaInfos.Where(h => h.Delta > positive * Multiplier).ToList(); var ControlNegative = deltaInfos.Where(h => h.Delta > negative * Multiplier).ToList();
.Where und .Average sind Linq-Methoden.
Das mit dem ⇒ ist ein Lambda-Statement.
Mit diesen Stichworten solltest du alles Nötige finden.
Zitat von cprogrammer
Aber der Abschnitt hier lautet ja "Grundlagen c#", weshalb ist es dann anrüchig Grundlagenfragen zu stellen ?
Du kannst hier gerne solche Fragen stellen, und du bekommst ja auch die Antworten. Aber eben auch diejenigen, die du nicht hören willst. Und auch wenn Abt manchmal etwas harsch ist, würde ich mir seine Worte zu Herzen nehmen.
Viele Grüße
Alf
Hallo Palladin007
Kennst du T4? Vielleicht ist das ja was.
Gruss
Alf
Hallo perlfred
Als was liegt denn die Geometry vor?
Ist das ein PathGeometry oder mehrere zusammengesetzte Pfade?
Gruss
Alf
Du hast das SelectedIndexChanged-Event nicht registriert. Siehe Bild.
Da frage ich mich aber, wie du mit dem Debugger in den Event-Handler lbDSGVO_SelectedIndexChanged reinlaufen konntest.
Imho sollte Bezeichnung der Bedingung mit einbezogen werden. Optimalerweise ist diese aussagekräfig genug um auf '== true' verzichten zu können. Also sollte eher der Name der Bedingung angepasst werden, statt '== true' zu verwenden.
if (prime.IsGreaterThan(100))
if (dictionary.TryGetValue(path, out path))
if (File.Exists(path))
Bei der negativen Bedingung kann die verwenden von 'is false' sinnvoll sein. Man sieht es besser als ein '!'. Ich finde die Schreibweise 'is false' besser als '== false' (siehe Herbivores Beitrag).
Ich gehe also mit Abt: 'is false' kann die Lesbarkeit erhöhen, '== true' nicht.
Also ist schonmal sichergestellt, dass die Methode 'LbDSGVO_SelectedIndexChanged' überhaupt aufgerufen wird.
Durch den Code hier, sollte sichergestellt sein, dass die Datei existiert.
// Check if the file exists
if (!File.Exists(filePath))
{
MessageBox.Show("File not found.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
Wie ist denn der Wert von filePath? Existiert diese Datei tatsächlich, und ist der Inhalt korrekt?
Wenn du mit dem Debugger durchsteppst, kommst du zu dieser Zeile? Was passiert danach?
rtbDatei.LoadFile(filePath, RichTextBoxStreamType.RichText);
Hallo Runenmeister
Häng dich mal mit dem Debugger in die MethodelbDSGVO_SelectedIndexChanged
rein und steppe da durch.
[Artikel] Debugger: Wie verwende ich den von Visual Studio?
Gruss
Alf
Hallo sacoma
Weil ich länger nichts mehr mit WPF gemacht habe, habe ich mir das Thema mal als Fingerübung genommen und Cavemans Ansatz weiterverfolgt.
Für die tabellenartige Darstellung ist nicht primär das ItemsControl relevant, sondern die Eigenschaft ItemsPanel. Die gibt es auch am ListView. Der Unterschied zwischen ItemsControl und ListView ist im wesentlichen das Selections-Verhalten.
Back to topic: Ich habe ein View für die Hochregale erstellt und eines für die Lagerplätze.
Lagerplatz aka RegalFach: der Status ist ein Enum und wird mit dem Converter in eine Farbe umgewandelt.
<UserControl.Resources>
<local:RegalFachStatusToBrushConverter x:Key="regalFachConverter"/>
</UserControl.Resources>
<ItemsControl ItemsSource="{Binding AllRegalFach}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="2" BorderBrush="{Binding Status, Converter={StaticResource regalFachConverter}}">
<TextBlock Text="{Binding Id}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
HochregalViewModel hat eine ObservableCollection, die kann die UI über Änderungen benachrichtigen.
public class HochregalViewModel : INotifyPropertyChanged
{
public ObservableCollection<RegalFachViewModel> AllRegalFach { get; }
public HochregalViewModel(IList<RegalFachViewModel> allRegalFach)
{
AllRegalFach = new ObservableCollection<RegalFachViewModel>(allRegalFach);
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Mehrere Hochregale mit der ItemsPanel-Eigenschaft nebeneinander stellen:
<ItemsControl ItemsSource="{Binding AllHochRegal}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:HochregalView />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Damit solltest du schonmal was anfangen können. Den Rest kann man sich zusammenreimen.
Wichtig ist die Aufteilung zwischen ViewModel und Model. Das RegalFachViewModel (er)hält die Daten vom RegalFach. RegalFach kommt aus dem Repository, dass den Datenbank-Zugriff kapselt. MVVM ist eine Technik für die UI. Les dir dazu nochmal den von FZelle verlinkten Artikel durch und am Besten auch https://mycsharp.de/forum/threads/111860/artikel-drei-schichten-architektur.
Gruß
Alf
Hallo echdeneth
Ich verstehe deine Frage nicht.
Eventuell könntest du dein Binding auf SelectedItem noch mit UpdateSourceTrigger=PropertyChanged ausstattest.
Gruss
Alf
Ich glaube deine Action-Properties müssen noch mit der UI über Änderungen kommunizieren.
Das heisst INotifyPropertyChanged für Action implementieren, oder ObservableObject.
Kann sein, dass du aus dem record dann ein class machen musst. Weiss ich nicht genau.
public record Action() : ObservableObject, IAction
{
[ObservableProperty]
public string Id { get; set; } = Constants.NotAvailable;
[ObservableProperty]
public long Timestamp { get; set; } = 0L;
[ObservableProperty]
public string Value { get; set; } = Constants.NotAvailable;
}
Gruss
Alf
Ja, die Diskussion ist etwas ausgeartet. 😁
Für deinen Anwendungsfall hast du ja eine gute Lösung gefunden. 👍
Mir ging es in erster Linie darum, dass niemand diesen Thread liest und dann denkt er könnte mit SecureString seine Kundendaten sichern.
Auch hier wieder die Frage, was ist konkret die bessere Alternative?
Ich kann meine Empfehlung nur nochmal wiederholen, für Security etablierte Systeme zu benutzen. Das kommt natürlich drauf an, wie der UseCase ist. In einer Windows-Domain würde man also ActiveDirectory verwenden, im Web einen passenden Anbieter.
Viele Grüsse