Laden...

Forenbeiträge von Alf Ator Ingesamt 748 Beiträge

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.

30.08.2023 - 15:40 Uhr

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

29.08.2023 - 10:16 Uhr

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?

28.08.2023 - 15:28 Uhr

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

03.08.2023 - 09:14 Uhr
[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

28.07.2023 - 09:29 Uhr

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.

26.07.2023 - 08:10 Uhr

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

24.04.2023 - 15:21 Uhr

Hallo perlfred

Als was liegt denn die Geometry vor?
Ist das ein PathGeometry oder mehrere zusammengesetzte Pfade?

Gruss
Alf

19.04.2023 - 13:48 Uhr

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.

18.04.2023 - 10:55 Uhr

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.

18.04.2023 - 09:52 Uhr

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);
17.04.2023 - 18:27 Uhr

Hallo Runenmeister

Häng dich mal mit dem Debugger in die MethodelbDSGVO_SelectedIndexChangedrein und steppe da durch.

[Artikel] Debugger: Wie verwende ich den von Visual Studio?

Gruss
Alf

06.04.2023 - 09:10 Uhr

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

03.04.2023 - 09:12 Uhr

Hallo echdeneth

Ich verstehe deine Frage nicht.

Eventuell könntest du dein Binding auf SelectedItem noch mit UpdateSourceTrigger=PropertyChanged ausstattest.

Gruss
Alf

15.03.2023 - 17:19 Uhr

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

15.03.2023 - 16:44 Uhr

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