Laden...

Forenbeiträge von Alf Ator Ingesamt 764 Beiträge

20.03.2024 - 11:51 Uhr

Hallo Ralf2022

Ich vermute das TCPServerStopp nicht aufgerufen wird. Setze doch mal einen Breakpoint und prüfe das. [Artikel] Debugger: Wie verwende ich den von Visual Studio?

Hast du den TCP/IP-Server asynchron gestartet?

Gruss
Alf

25.01.2024 - 09:17 Uhr

Zitat von CSharpNewbie2022

Zitat von Alf Ator

Du könntest ein Haupt-ViewModel benutzen, dass die anderen ViewModels hält und mit Daten füttert.
Ich habe dir mal ein minimales Beispiel angehängt.

Ich hatte jetzt doch lust etwas wenig zu schlafen und mich daran zu setzen Dein Beispiel ist doch dahingegen anders als mein Fall, da ich mehrere Views habe, es ist ähnlich zu dem Fall bei dem Verlinkten anderen Beitrag.

Das Beispiel lässt sich doch supereinfach auf deinen Fall erweitern. Ich dachte das reicht aus.

Jetzt frage ich mich ok, Text zu Zahl aus der DB ist Teil des Models/Businessmodels, Laden des Inhalts der Zahlen aus einer Datei und Speichern in eine Datei auch auch?

Ja. Schau dir dazu das Repository-Pattern an.

Was passiert dann im ViewModel, werden dort nur die Klassen DB und File laden als Objekte erstellt und die Methoden genutzt + Button Commands und Alle Binding Variablen?

Ja.

Versuche ich soviel in Modell zu legen, wie geht?

Es geht darum, Geschäftslogic und UI(-Logic) voneinander zu trennen.

Die Methoden des Modells spucken als return values dann strings oder listen aus und diese werden im Viewmodell an die Binding variablen übergeben?

Ja.

Ich hab das Beispiel etwas erweiter.

24.01.2024 - 11:53 Uhr

Du könntest ein Haupt-ViewModel benutzen, dass die anderen ViewModels hält und mit Daten füttert.
Ich habe dir mal ein minimales Beispiel angehängt.

22.01.2024 - 16:12 Uhr

Okay, sorry für den unverständlichen Beitrag 😦

Der Name CellViewModel ist etwas ungünstig gewählt. Ich hatte mich an deinem Beispielcode orientiert. 
RowViewModel wäre besser. Du kannst im RowViewModel' für jede Spalte, die im DataGrid angezeigt werden soll ein Property anlegen. Für 50 Spalten also 50 Properties.

Die Lösung passt eventuell nicht zu deinem UseCase. Was sollte denn mit den angezeigten Daten gemacht werden? Sollen die nur angezeigt, oder bearbeitet werden? Ändert sich das Excel-Dokument regelmässig, oder bleibt es gleich?

22.01.2024 - 14:27 Uhr

Hallo Caveman

Wie Abt schon gemeint hat, ObservableCollection nur einmal zuweisen und binden.


        public ObservableCollection<Model> Items { get; } = new ObservableCollection<Model>();

Statt das Model im View zu verwenden könntest du auch ein ViewModel verwenden. Siehe Bild.

Edit:

Das wäre dann übrigens auch die Lösung für dein Problem mit List<List<T>>

            <DataGrid.Columns>
                <DataGridTextColumn Header="Header" Binding="{Binding CellValue}" />
            </DataGrid.Columns>
            <behav:Interaction.Triggers>
                <behav:EventTrigger EventName="AutoGeneratingColumn" SourceObject="{Binding ElementName=TestDataGrid}" >
                    <behav:InvokeCommandAction Command="{Binding ColumnGeneratingEvent, Mode=OneWay}" PassEventArgsToCommand="True" />
                </behav:EventTrigger>
            </behav:Interaction.Triggers>

Entweder Autogenerate Columns, oder Columns fest definieren. Beides gleichzeitig kommt nicht so gut.

16.01.2024 - 10:39 Uhr

Servus Caveman

Das sieht doch schonmal ganz gut aus. Von mir noch ein paar Anmerkungen.

ObservableCollection verwende ich eher im UI-Context. Wurde aber schon erwähnt. Die ObservableCollection kann dann im ViewModel gefüllt werden. Je nach Komplexität kann der User dann noch in ein UserViewModel konvertiert werden.

Erstellen und Anzeigen vom Window mache ich nicht im App-Konstruktor, sondern:

    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            
            // hier
        }
    }

Du hast View und ViewModel als Singleton erstellt. Sofern es dafür keine speziellen Gründe gibt, würde ich die transient machen. ViewModel würde ich generell nicht als Singleton machen, sonst hast du auf einmal Daten auf der View, die da nicht sein sollten.

Gruss
Alf

11.01.2024 - 09:57 Uhr

Okay, ich verstehe das Problem.

Die Width von der ersten Column ist auf Auto gesetzt. Durch das aufklappen des Expanders wird die Column breiter.
Um das zu verhindern, kannst du die Column-Width fest auf 200 setzten.

Was mit dem Expander nicht geht, ist dass der Expander die Column 'verlässt'. Dafür müsstest du dann z.B. ein Popup verwenden.

Du könntest das gewünschte Verhalten evt. auch mit Grid.ColumnSpan="3" erreichen.

Gruss
Alf

09.01.2024 - 17:54 Uhr

Hallo CSharpNewbie2022

Stell doch den ZIndex vom Expander testweise mal auf 1.

Gruss
Alf

Edit:
Oder so:

<Rectangle Fill="LightGray" Width="200" Height="100" Grid.ZIndex="2" />
<Ellipse Fill="LightBlue" Width="100" Height="100"  Grid.ZIndex="3"/>
<Expander HorizontalAlignment="Left" VerticalAlignment="Top" x:Name="myExpander" Grid.ZIndex="4" ExpandDirection="Right">
09.01.2024 - 14:37 Uhr

Hatte dein Projekt mal aufgemacht um das anzuschauen und hab ganz, ganz grob sowas wie MVVM und Schichten reingemacht.

09.01.2024 - 12:03 Uhr

Les die Frage von BlonderHans nochmal genau. Zwischen 'TblProgramminfo' und 'TblScheibendaten' besteht keine (für uns erkennbare) Beziehung. Wie ist da die Verbindung?

02.01.2024 - 10:08 Uhr

Hallo Andi153

In der Doku steht, dass ServiceBase in der Assembly "System.ServiceProcess.ServiceController.dll" ist.

Gruss
Alf

02.01.2024 - 09:45 Uhr

Zitat von mezzo80

Als nächstes möchte ich aber in Window1 im Codebehind direkt auf den String von FirstName zugreifen.

Hallo mezzo80

Da liegt schon der Fehler. Mit MVVM wird das anders gelöst. Was genau hast du vor?

Gruss
Alf

13.12.2023 - 17:26 Uhr

Hallo ill_son

Bin mir nicht sicher ob ich den Aufbau richtig verstanden habe. Ich denke es fehlen noch Informationen um die Fragen zu beantworten.

Wo werden denn die Channel-Objekte (??) gehalten und wo werden sie erzeugt? Im Repository?

wer ist dann für den Aufruf von Dispose() zuständig?  Ich würde jetzt sagen das Repository.

Dann ja.

Sollte der Channel dann ein Disposed-Event haben?

Nur wenn es benötigt wird.

Gruss
Alf

13.12.2023 - 09:59 Uhr

Du hast ja einen Link bezüglich eines Schichtmodels gepostet. Aber ist das nicht bereits das, was MVVM macht? Auf mich macht es den Eindruck, als wäre das so. Ich kann mich da aber auch irren.

Einfache Antwort: MVVM ist im Schichtenmodel im UI-Teil einzuordnen.

(Natürlich ist das Thema komplexer, aber das spar ich mir hier mal.)

12.12.2023 - 14:11 Uhr

Hallo StayCalm

Zitat von StayCalm

Die dritter GroupBox "Combine" hat einen Button und ein Label. Wenn man in der dritten GroupBox den Button „Combine“ klickt, soll im Label der String aus der Person-TextBox mit dem String des Animal-TextBox zusammengeführt werden.

Wenn es sich bei dem Zusammenführen von Text um komplexe Geschäftslogik handelt, dann sollte sich diese in der entsprechenden Schicht befinden:
https://mycsharp.de/forum/threads/111860/artikel-drei-schichten-architektur

Dein CombineViewModel bekommt dann ein ICommand-Property, dass vom MainViewModel aus gesetzt werden kann, und vom Button ausgelöst wird.

// So ähnlich könnte das aussehen. Habe es ohne Testen runtergeschrieben.
public MainViewModel(CombinationService combinationService)
{
  this.combineViewModel = new CombineViewModel
  {
    CombineCommand = new RelayCommand<string>(() => this.CombinationResult = combinationService.Combine(this.personViewModel.Name, this.animalViewModel.type));
  };
}

Gruss
Alf

12.12.2023 - 13:03 Uhr

Hallo JanBauer

CameraCaptureUI tut wohl nicht mit WinForms, man soll wohl MediaCapture verwenden:
https://learn.microsoft.com/en-us/uwp/api/windows.media.capture.mediacapture?view=winrt-22621

Da gibt es auch ein Beispiel.

Gruss
Alf

07.12.2023 - 09:50 Uhr

Hö? Was machst du? Du brauchst nur ein Grid. Und warum ist da immer noch md und sm?

https://mudblazor.com/features/breakpoints#breakpoints

07.12.2023 - 08:46 Uhr

Hallo Bronstein

Du hast die Breite so konfiguriert: md="4"; mach das mal weg.

Gruss
Alf

22.11.2023 - 07:49 Uhr

Hallo pollito

Es gibt fertige Komponenten zu kaufen, die das können.

Alternativ in Pdf oder Html konvertieren und anzeigen.

Gruss
Alf

20.11.2023 - 12:27 Uhr

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.

17.11.2023 - 09:28 Uhr

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?

16.11.2023 - 10:05 Uhr

Möglicherweise der Virenscanner auf dem anderen Rechner.

16.11.2023 - 10:00 Uhr

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.

14.11.2023 - 10:50 Uhr

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

11.11.2023 - 18:32 Uhr

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. check

Wird 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. 😃

09.11.2023 - 10:56 Uhr

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.

08.11.2023 - 14:32 Uhr

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>
08.11.2023 - 09:42 Uhr

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

https://www.c-sharpcorner.com/UploadFile/ptmujeeb/wpf-mvvm-pattern-a-simple-tutorial-for-absolute-beginners/

Ausserdem empfehle ich dir noch diesen Artikel:
https://mycsharp.de/forum/threads/111860/artikel-drei-schichten-architektur

Gruss
Alf

01.11.2023 - 10:09 Uhr

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

31.10.2023 - 13:01 Uhr

Hallo Timm2023

Bei WPF benutzt du am besten das MVVM-Pattern:

https://mycsharp.de/forum/threads/118261/artikel-mvvm-und-databinding

https://www.c-sharpcorner.com/UploadFile/ptmujeeb/wpf-mvvm-pattern-a-simple-tutorial-for-absolute-beginners/

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

18.10.2023 - 16:07 Uhr

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

18.10.2023 - 10:27 Uhr

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)

18.10.2023 - 09:44 Uhr

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

16.10.2023 - 14:56 Uhr

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.

16.10.2023 - 12:04 Uhr

Zitat von Moma2023

Aktuelle Fehlermeldung: System.ArgumentException: "Keyword not supported: 'trustedconnection'."

Müsste das nicht "Trusted_Connection=True" sein?

16.10.2023 - 10:52 Uhr

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

06.10.2023 - 17:50 Uhr

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);
    }
}
06.10.2023 - 15:02 Uhr

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

05.10.2023 - 08:07 Uhr

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

13.09.2023 - 15:52 Uhr

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.

13.09.2023 - 15:09 Uhr

Ist die Referenz auf die WindowsBase eingetragen?

11.09.2023 - 12:34 Uhr

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>
11.09.2023 - 09:30 Uhr

<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.

08.09.2023 - 18:38 Uhr

Hi theSoulT

Ich vermute du musst als Tricker-Target das 'PackIconMaterial' nehmen und nicht den Button.

Gruß
Alf

08.09.2023 - 10:01 Uhr

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.

https://ninjatrader.com/support/helpGuides/nt8/NT%20HelpGuide%20English.html?creating_your_own_addon_window.htm

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 😃

05.09.2023 - 14:55 Uhr

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.

05.09.2023 - 13:42 Uhr

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

04.09.2023 - 10:33 Uhr

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

31.08.2023 - 11:26 Uhr

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.