Laden...

Forenbeiträge von TheLion092 Ingesamt 17 Beiträge

19.12.2019 - 15:57 Uhr

Aaaaalsoo..

Ich habe folgendes in der MainWindow.xaml.cs stehen:


using NTFStool.ViewModels;
using System.Windows;

namespace NTFStool.Views
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainViewModel();
        }
    }
}

Das ist ein Ausschnitt aus dem MainViewModel:


using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using NTFStool.Models;
using NTFStool.AppLogic;
using NTFStool.Helpers;

namespace NTFStool.ViewModels
{
    public class MainViewModel : PropertyChangedEvent
    {

        //=> Liste der User
        private ObservableCollection<User> userlist = new ObservableCollection<User>();
        public ObservableCollection<User> Userlist
        {
            get { return userlist; }
            set { userlist = value; NotifyPropertyChanged(); }
        }

        //=> "Vorname" sichtbar
        private bool vornameEnabled = true; // Default: Sichtbar
        public bool VornameEnabled
        {
            get { return vornameEnabled; }
            set { vornameEnabled = value; NotifyPropertyChanged(); }
        }

        //=> "Nachname" sichtbar
        private bool nachnameEnabled = true; // Default: Sichtbar
        public bool NachnameEnabled
        {
            get { return nachnameEnabled; }
            set { nachnameEnabled = value; NotifyPropertyChanged(); }
        }

        .
        .
        .

    }
}

Im View ist das DataGrid, welches eine Datenbindung zur ObservableCollection hat.
Die Spalten des DataGrid sowie einige DockPanel-MenuItem's haben eine Datenbindung zu z.B. "Vorname sichtbar" oder "Nachname sichtbar".

Das funktioniert auch wunderbar. Wenn ich die Properties "Vorname sichtbar" oder "Nachname sichtbar" usw. nicht im ViewModel sehen will, sondern in eine eigene Klasse verschiebe, funktioniert die Datenbindung zwischen dem ControlItem im View und der Property im ViewModel nicht mehr:


<DataGrid  x:Name="datagrid" HeadersVisibility="Column" IsReadOnly="True" AutoGenerateColumns="False" ItemsSource="{Binding Userlist, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" Focusable="False">
...

<MenuItem Name="Ansicht_Vorname" Header="Vorname" IsCheckable="True" IsChecked="{Binding VornameEnabled}"/>

Ich habe derzeit auch noch eine zweite kleine Frage:
Ich habe einiges an Code, der im ViewModel stand in eine "Logic"-Klasse ausgelagert, auf die ich aus dem ViewModel zugreife. Mein Gedanke war einfach, das ViewModel etwas aufgeräumter zu bekommen. Manchmal weiß ich aber gar nicht, ob das überhaupt Sinn macht.
Was gehört denn alles an "Code-behind" ins ViewModel (Abgesehen von einer Klasse User natürlich, weil das gehört ja ins Model)? Ist es normal, dass das ViewModel ziemlich voll wird ?

Liebe Grüße

18.12.2019 - 16:09 Uhr

Hallo,

mit der Zeit sammeln sich im ViewModel ja doch eine ganze Menge an Properties an. Diese würde ich der Übersicht halber gerne in eine eigene Klasse auslagern. Wie bekomme ich das dann mit dem DataContext hin. Der DataContext wurde bei mir im MainWindow.xaml.cs bereits zum ViewModel festgelegt, weil sich im ViewModel eine ObservableCollection befindet, die im View mit einem DataGrid verbunden ist.

Also kurz gesagt: Wie bekomme ich einen zweiten, zusätzlichen DataContext zu der ausgelagerten Properties-Klasse hin ?

Macht es überhaupt Sinn, die Properties auszulagern oder ist das unüblich ?

Liebe Grüße

16.09.2019 - 15:25 Uhr

Vielen dank an euch, für die Hilfe und Hinweise 😃

14.09.2019 - 15:01 Uhr

Ich denke, ich habe es jetzt hinbekommen, jedenfalls funktioniert es. Ich übergebe beim RelayCommand im ViewModel, der Methode aus der Logik-Klasse jetzt einfach die ObservableCollection aus dem ViewModel und returne das ganze wieder. Ob das jedoch richtig ist, weiß ich trotzdem nicht. Mich würde also interessieren, wie man mit Code-behind von Buttons etc. am besten umgeht. Schreibt man das alles ins ViewModel oder kann man das so wie ich in eine Logik-Klasse auslagern ?

Ausßerdem habe ich jetzt das "PropertyChangedEvent" und den "RelayCommand" in einen Helpers-Ordner verschoben und implementiere im ViewModel und im Model die Klasse "PropertyChangedEvent". Ist das so in Ordnung ?

Liebe Grüße

14.09.2019 - 11:25 Uhr

Hmm.. da der Setter der ObservableCollection (Userlist) ein "NotifyPropertyChanged()" hat, müsste ich ja wenn ich die Userlist in die Logik-Klasse verschieben würde, dort auch das INotifyPropertyChanged implementieren. Ich bin mir nicht sicher, ob das richtig ist. Die Überlegung war einfach, dass mal relativ viel Logik geschrieben werden soll, weshalb ich das auslagern will. Oder ist es üblich, dass man die gesamte Button-Logik mit in das ViewModel schreibt ? Oder verstehe ich wieder was falsch ?

Liebe Grüße

13.09.2019 - 17:33 Uhr

So, nach einiger Zeit und viel nachlesen denke ich, dass ich MVVM ganz gut in meinem Projekt umgesetzt habe. Gerne dürft ihr mal drüberschauen, ob ich alles richtig gemacht habe, oder mir Tipps geben, wo man noch was besser machen kann.

Jedoch habe ich auch noch eine kleine Stelle, bei der ich nicht weiterkomme.
Ich habe jetzt eine eigene Klasse mit dem Namen "UserlistLogic" erstellt in der Methoden stecken, die beim Klicken eines Buttons ausgelöst werden sollen (Einfach um die Button-Logik auszulagern). Dazu habe ich im ViewModel RelayCommands erstellt. Ebenso habe ich im ViewModel eine ObservableCollection (Userlist) erstellt, sowie die UserlistLogic Klasse deklariert und instanziiert. Leider kann ich von der UserlistLogic Klasse nicht auf die erstellte ObservableCollection (Userlist) im ViewModel zugreifen. Ich denke nicht, dass das besonders schwierig ist, aber ich komme leider nicht auf die Lösung.

Kann mir da eventuell jemand weiterhelfen ?

Hier der Link zum Repository:
https://github.com/TheLion092/NTFS-Tool

Liebe Grüße

11.09.2019 - 13:35 Uhr

Das sieht super aus, vielen Dank 😃

11.09.2019 - 13:13 Uhr

Hallihallo,
ich hab Google bereits dazu gefragt, aber eine wirklich schöne Doku habe ich bisher nicht dazu gefunden. Wie macht ihr das mit der Benennung ? Ich meine konkret folgendes:

Groß- und Kleinschreibung von:

  • Variablennamen
  • Instanziierungen
  • Methoden

Benennt ihr alles auf Englisch oder manches auch auf Deutsch ?

Wie macht ihr das bei Propertys bei den privaten Variablen ? Manche schreiben diese im Gegensatz zur public-Variable einfach klein oder machen einen Unterstrich davor.

Kennt ihr vielleicht eine gute Doku, wo genau das beschrieben wird?

Liebe Grüße

23.08.2019 - 09:02 Uhr

Alles klar, werde ich machen. Dann erstmal vielen Danl für eure Hilfe und eure Geduld =)

22.08.2019 - 17:06 Uhr

Ok, mit Hilfe vom Output Windows habe ich es jetzt zum Laufen bekommen, danke erstmal dafür 🙂

Wenn ich der ?-> Klasse <-? "UserViewModel" jetzt eine weiteres Attribut vom Typ ObservableCollection<> hinzufügen wollen würde, dann sollte man dafür wieder ein ViewModel erstellen, richtig ?
Und wenn ich dann am Ende im DataGrid, Attribute aus der neuen ObservableCollection<> eine Ebene tiefer, nennen wir sie jetzt mal ObservableCollection<ADgroups> anzeigen lassen möchte, dann kann ich in XAML den entsprechenden Context oder Pfad auswählen ?

also z.B. so ? (Es ist mit Sicherheit nicht richtig)


<DataGrid Margin="10,50,10,25" IsReadOnly="True" AutoGenerateColumns="False" ItemsSource="{Binding Users, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Vorname" Binding="{Binding Vorname}"/>
            <DataGridTextColumn Header="Nachname" Binding="{Binding Nachname}"/>
            <DataGridTextColumn Header="Alter" Binding="{Binding Alter}"/>

            <!-- Neues Binding eine Ebene tiefer -->
            <DataGridTextColumn Header="Anzahl AD-Gruppen" Binding="{Binding UserViewModel/gruppenanzahl}"/>
        </DataGrid.Columns>
</DataGrid>

nun gesehen, dass es im Xaml von Threadstarter auch schon falsch ist.

Ja, genau das war der Fehler 😁

22.08.2019 - 14:06 Uhr

Ok ich glaube langsam, es zu verstehen bzw. nachvollziehen zu können. Der C# Code hat mir jedenfalls schonmal lerntechnisch weitergeholfen.

Verstehe ich es richtig, dass wenn man in eine Klasse diese "NotifyPropertyChanged"-Methode einbaut, man es dann ViewModel nennt ?

Was ich noch nicht ganz nachvollziehen kann ist, warum man hier das UserViewModel in das MainViewModel stecken muss. Das UserViewModel gibt doch schon Meldung darüber, wenn sich ein Wert ändert !?

Und wieso hat es funktioniert, die "List<User> userlist" gegen ein "ObservableCollection<User> userlist" zu tauschen und dann einfach zu sagen "datagrid.ItemSource = userlist" und was ist falsch daran, bzw. welche Probleme bingt es mit sich. Oder ist das einfach nur die Regel, dass man das nicht machen soll ?

Dass die OC veraltet ist, habe ich wohl doch falsch verstanden, sorry.

Ich habe jetzt jedenfalls mal versucht, das DataGrid in XAML zu binden. Scheint aber wohl auch noch nicht so ganz richtig zu sein:


<DataGrid x:Name="datagrid" Margin="10,50,10,25" ItemsSource="{Binding Source=User, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Vorname" Binding="{Binding Vorname}"/>
                <DataGridTextColumn Header="Nachname" Binding="{Binding Nachname}"/>
                <DataGridTextColumn Header="Alter" Binding="{Binding Alter}"/>
            </DataGrid.Columns>
        </DataGrid>

Liebe Grüße und Durchhaltevermögen mit mir 😁

22.08.2019 - 10:23 Uhr

Wo hast Du das gelesen?

Im Artikel https://www.codingfreaks.de/2017/08/14/wpf-und-mvvm-richtig-einsetzen-teil-5/ steht:

Der hier gezeigte Ansatz ist scheinbar sehr charmant. Man hat etwas extrem einfaches im ViewModel (ObservableCollection<T>), bindet dagegen und alles scheint sauber zu funktionieren. Das Problem bei dem Beispiel ist die Performance. Um das zu verstehen, muss man sich vergegenwärtigen, dass das UI-Element DataGrid in unserem Beispiel direkt auf den Daten operiert. Außerdem beeinflussen die Daten direkt das Erscheinungsbild des UI. Bei 10 oder 100 Elementen spielt das noch keine Rolle. Haben wir aber z.B. 10.000 Elemente in der Datenquelle, wird das Bein recht schnell dick.

Ein weiterer wichtiger Nachteil unserer Lösung ist, dass wir auf das Multi-Threading acht geben müssen. Würde aktuelle ein anderer Thread als der UI-Thread Elemente auf der ObservableCollection<T> ändern, würden wir recht schnell Exceptions im UI bekommen

Gute Alternative:
Gerade aus Sicht von MVVM bietet sich ein anderer Typ perfekt für die gewünschte Implementierung an: ICollectionView. Dieser Typ ist schon von seinem Grundaufbau nahezu perfekt für MVVM geeignet, da er die Daten von der Repräsentation trennt. Der Einsatz von ICollectionView führt also quasi zu MVVM in MVVM. Sehen wir uns das genauer an.

Nachdem ich in meinem Code die List<> gegen eine ObservableCollection<> getauscht hatte, funktionierte es auf einmal und verhielt sich so, wie ich es wollte. Ich vermute aber, dass das trotzdem nicht richtig ist, wie ich es gemacht habe, da ich immer noch nix mit ViewModel gemacht habe.

Ich habe jetzt mal ein bisschen weiter gegoogelt und versucht, das zu implementieren. Jedoch leider ohne Erfolg 😦


using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;

namespace Test
{
    public partial class MainWindow : Window
    {
        //Private Felder (Variablen)
        private ObservableCollection<User> userlist;

        public MainWindow()
        {
            InitializeComponent();
            ViewModel = new MainViewModel();
        }
        public MainViewModel ViewModel
        {
            get { return DataContext as MainViewModel; }
            set { DataContext = value; }
        }


        private void ClickEvent(object sender, RoutedEventArgs e)
        {
            userlist.Add(new User() { vorname = "Max", nachname = "Mustermann", alter = 15 });
        }

        private void dgLoaded(object sender, RoutedEventArgs e)
        {
            // ObservableCollection<> Instanziieren
            userlist = new ObservableCollection<User>();               
        }
    }

    public class MainViewModel : INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string info)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(info));
            }
        }

        public MainViewModel()
        {

        }

        private ObservableCollection<User> _userlist;

        public ObservableCollection<User> Userlist
        { 
            get { return _userlist; }
            set { Userlist = value; OnPropertyChanged("Userlist"); }
        }
    }

    class User
    {
        public string vorname { get; set; }
        public string nachname { get; set; }
        public int alter { get; set; }
    }
}

21.08.2019 - 17:21 Uhr

Ich probiere derzeit viel mit Bindings rum und versuche ein DataGrid an eine List zu binden. Ich habe jetzt viel darüber gelesen, z.B. dass man bei einem einfachen Binding das Problem hat, dass das DataGrid sich bei Wertänderung in der Quelle nicht automatisch aktualisiert. Außerdem habe ich gelesen, dass BindingList<T> und ObservableCollection<T> nicht mehr verwendet werden sollen. Am besten soll wohl "ICollectionView" sein. Auch wenn ich jetzt viel dazu gelesen habe, vor allem hier: https://www.codingfreaks.de/2017/08/14/wpf-und-mvvm-richtig-einsetzen-teil-5/ und auch hier [Artikel] MVVM und DataBinding , benötige ich wohl doch nochmal einen kleinen Lösungsvorschlag, das ganze mit der besten Methode (dies scheint wohl "ICollectionView" zu sein) umzusetzten.

Seid nicht zu grob zu mir, ich bringe mir das alles grade selber bei 😃

XAML:


<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Test"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" WindowStartupLocation="CenterScreen">

    <Grid>
        <Button x:Name="button" Content="User erzeugen" HorizontalAlignment="Left" Margin="10,10,0,0" Width="100" VerticalAlignment="Top" Click="ClickEvent"/>
        <DataGrid x:Name="datagrid" Margin="10,50,10,10" AutoGenerateColumns="True" IsReadOnly="True" Loaded="datagridLoaded"/>
    </Grid>
</Window>

MainWindow:


using System.Collections.Generic;
using System.Windows;

namespace Test
{
    public partial class MainWindow : Window
    {
        //Private Felder (Variablen)
        private bool loaded;
        private List<User> userlist;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void datagridLoaded(object sender, RoutedEventArgs e)
        {
             userlist = new List<User>();
             datagrid.ItemsSource = userlist;
        }

        private void ClickEvent(object sender, RoutedEventArgs e)
        {
            userlist.Add(new User() { vorname= "Hans", nachname= "Peter", alter = "42" });    
        }
    }

    class User
    {
        public string vorname { get; set; }
        public string nachname { get; set; }
        public int alter { get; set; }
    }
}

Liebe Grüße

01.08.2019 - 16:18 Uhr

Hallo,

ich habe eine kleine Anwendung mit einem DataGridView. Mit "DataGridView_Loaded" lege ich die Spaltennamen fest, lege die Spaltenbreiten fest und lege die ItemSource fest. FUnktioniert auch alles super. Wenn ich die Anwendung jetzt am laufen habe, ich in Windows den Benutzer wechsel und dann wieder zurück wechsel, dann wird nach dem Laden des Desktops im Programm "Loaded" erneut ausgeführt. Das macht sich bemerkbar, da das Programm dann abstürzt mit der Begründung, es gebe bereits eine Spalte mit dem Namen. Was kann ich tun ? "Initialized" funktioniert leider nicht, weil ich dann z.B. keine Spaltenbreite festlegen kann mit der Begründung

Fehlermeldung:
System.ArgumentOutOfRangeException: "Der Index lag außerhalb des Bereichs. Er darf nicht negativ und kleiner als die Sammlung sein.
Parametername: index"

Liebe Grüße

06.06.2019 - 17:37 Uhr

Ich werde mal etwas rumprobieren und mich dazu belesen.

Vielen Dank erstmal an alle 😃
Liebe Grüße

06.06.2019 - 10:58 Uhr

Hmm... wahrscheinlich verstehe ich es nur falsch, aber ich war eigentlich der Meinung, ich hätte das mit dem DataBinding gemacht. Sobald ich was in der DataTable ändere, ändern sich auch die Daten im DataGrid.


public DataTable dt { get; private set; } = new DataTable();

private void Datagrid_Loaded(object sender, RoutedEventArgs e)
{
	dt.Clear();
	dt.Columns.Add("IDM-Nummer", typeof(string));
	dt.Columns.Add("Vorname", typeof(string));
	dt.Columns.Add("Nachname", typeof(string));
	dt.Columns.Add("Berechtigung", typeof(string));
	dt.Columns.Add("Gruppe", typeof(string));
	Datagrid.ItemsSource = dt.DefaultView;
}


<DataGrid Grid.Row="1" x:Name="Datagrid" GridLinesVisibility="None" HeadersVisibility="Column" SelectionMode="Single" IsReadOnly="True" ItemsSource="{Binding}" Loaded="Datagrid_Loaded"/>

Den Aspekt, dass man keine DataTable mehr verwenden soll, sondern lieber eine List, werde ich mir nochmal anschauen.

05.06.2019 - 21:08 Uhr

Hallo 🙂

Kurz vorweg, ich bin Anfänger auf dem Gebiet der C#/WPF Programmierung, also bitte nich zu sehr haten =) Ich bin Systemadministrator und kein gelernter Programmierer.

Für mein Unternehmen bin ich derzeit dabei ein kleines Programm zu schreiben, was alle User die auf einen bestimmten Ordner auf einem Netzlaufwerk NTFS Rechte haben, auflistet. Sprich ich möchte sehen, wer z.B. auf G:\Verwaltung\Aufträge Lese- und Schreibrechte hat, und dies dann in einer Tabelle aufgelistet haben. Die erste Erleichterung: Mein Programm ist so gut wie fertig. Ich lasse mir alle AD-Gruppen für einen Ordner auslesen und lese dann aus diesen AD-Gruppen wiederum alle User aus. Die Benutzer werden in einer DataTable gespeichert und dann im Programm an ein DataGrid weitergegeben. Bedingt durch unsere ActiveDirectory-Architektur kommt es vor, dass User auf einen Ordner mehrmals über verschiedene Gruppen Lese-Schreibberechtigung bekommen. Bedeutet also, in meiner Tabelle habe ich Duplikate. Nun möchte ich diese doppelten Zeilen löschen, so dass nur noch eine da ist. Der Knackpunkt ist aber, dass für Duplikate in Spalte 1 unterschiedliche Werte in Spalte 4 und 5 stehen können. Die Spalte 1 mit der Mitarbeiter-Nummer ist hierbei eindeutig. Wie filtere ich jetzt die DataTable, dass sie mir das gewünschte Ergebnis anzeigt ?

Beispiel:
User für G:\Verwaltung\Aufträge

Mitarbeiter-Nummmer | Vorname| Nachname | Rechte | AD-Gruppe

155484 |Max | Mustermann | Lesen | verwaltung-read
154574 |Klaus | Müller | Lesen | verwaltung-read
154574 |Klaus | Müller | Schreiben | administratoren

Was ich haben möchte:

Mitarbeiter-Nummmer | Vorname| Nachname | Rechte | AD-Gruppe

155484 |Max | Mustermann | Lesen | verwaltung-read
154574 |Klaus | Müller | Lesen, Schreiben | verwaltung-read, administratoren

Ich habe hier aktuell eine Funktion, welche mir zuverlässig Duplikate entfernt, jedoch werden dadurch keine Zellen aus Spalte 4 und 5 gemerged


public DataTable RemoveDuplicateRows(DataTable dTable, string colName)
        {
            Hashtable hTable = new Hashtable();
            ArrayList duplicateList = new ArrayList();

            //Add list of all the unique item value to hashtable, which stores combination of key, value pair.
            //And add duplicate item value in arraylist.
            foreach (DataRow drow in dTable.Rows)
            {
                if (hTable.Contains(drow[colName]))
                {
                    duplicateList.Add(drow);
                }
                else
                {
                    hTable.Add(drow[colName], string.Empty);
                }
            }
            //Removing a list of duplicate items from datatable.
            foreach (DataRow dRow in duplicateList)
            {
                dTable.Rows.Remove(dRow);
            }
            //Datatable which contains unique records will be return as output.
            return dTable;
}

Vielleicht kann mir ja jemand helfen 😁
Liebe Grüße