Hallo,
ich möchte gerne die Eingabe eines Barcode-Scanner erfassen (USB Modus, läuft als Tastatur Eingabe).
Das ganze soll in einem ContentControl Bereich stattfinden. Zum Testen habe ich mir jetzt eine ganze einfache Version gebaut (siehe unten).
Wie bekomme ich es jetzt hin, dem UserControl einen KeyDown Event hinzuzufügen?
Der Scanner sendet ja wie eine Tastatur jedes Zeichen als Tastenanschlag und zum Schluss ein Enter. Ich möchte nun jedes Zeichen erfassen und prüfen ob es ein Enter ist oder nicht. Wenn nicht, dann soll das Zeichen einem String hinzugefügt werden, wenn es ein Enter ist, soll der String verarbeitet werden.
Ich möchte keine TextBox oder ähnliches nutzen.
Wie das ganze funktioniert, wenn ich kein MVVM Konzept nutze, habe ich ja gefunden aber mit MVVM bekomme ich es nicht hin.
MainWindow.xaml
<Window x:Class="resperLaMa.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:resperLaMa"
xmlns:local1="clr-namespace:resperLaMa.Pages"
xmlns:local2="clr-namespace:resperLaMa.ViewModels"
mc:Ignorable="d"
Title="Test"
WindowStartupLocation="CenterScreen" WindowState="Maximized">
<Window.Resources>
<DataTemplate DataType="{x:Type local2:BarcodeViewModel}">
<local1:Barcode/>
</DataTemplate>
</Window.Resources>
<DockPanel LastChildFill="True">
<ContentControl x:Name="Pages" DockPanel.Dock="Right" Content="{Binding SelectedViewModel}"/>
</DockPanel>
</Window>
MainWindow.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
}
MainWindowViewModel.cs
namespace resperLaMa.ViewModels
{
class MainWindowViewModel : BaseViewModel
{
private object selectedViewModel;
public object SelectedViewModel
{
get { return selectedViewModel; }
set
{
selectedViewModel = value;
OnPropertyChanged("SelectedViewModel");
}
}
public MainWindowViewModel()
{
SelectedViewModel = new BarcodeViewModel();
}
}
}
Barcode.xaml:
<UserControl x:Class="resperLaMa.Pages.Barcode"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:resperLaMa.Pages"
mc:Ignorable="d">
<StackPanel>
<Label Content="Bitte Code scannen" />
</StackPanel>
</UserControl>
BarcodeViewModel.cs:
namespace resperLaMa.ViewModels
{
class BarcodeViewModel : BaseViewModel
{
public BarcodeViewModel ()
{
}
}
}
BaseViewModel:
namespace resperLaMa.ViewModels
{
public abstract class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Das erspart dann auch das string.Join.
Das String.Join fand ich ganz praktisch wegen dem eingebauten Seperator
Und ich würde das selbst implementieren komplett sein lassen, wenn es nicht der eigentliche Sinn ist das mit Attributen und Refelection zu lernen.
> hat das alles schon implementiert incl. Schemaupdate und allem.
An dem Prinzip versuche ich mich zu orientieren. Aber so lerne ich am besten, wenn ich solche Funktionen nachbaue und versuche zu verstehen wie das funktioniert.
Hallo gfoidl,
danke für die Anpassung des Titels und die Verschiebung ins richtige Forum.
Zu Punkt 2:
Ich habe das ganze mal mit einem StringBuilder umgesetzt, war es ungefähr das was du meintest:
private void createTable<T>()
{
PropertyInfo[] props = typeof(T).GetProperties();
string[] cols = new string[props.Count()];
for(int i = 0; i < props.Count(); i++)
{
StringBuilder colString = new StringBuilder(String.Format("'{0}'", props[i].Name));
var attrs = props[i].GetCustomAttributes(true);
foreach (DbAttributes attr in attrs)
{
if (attr.IsInteger) colString.Append(" INTEGER");
if (attr.IsText) colString.Append(" TEXT");
if (attr.IsPrimary) colString.Append(" PRIMARY KEY");
if (attr.IsAuto) colString.Append(" AUTOINCREMENT");
}
cols[i] = colString.ToString();
}
string createTable = String.Format("CREATE TABLE IF NOT EXISTS '{0}' ({1});", typeof(T).Name, String.Join(", ", cols));
queryNon(createTable);
}
Zu Punkt 1 und 3:
Da muss ich wohl noch etwas Zeit investieren. Da mein Englisch nicht sehr gut ist, brauche ich für solche etwas komplexeren Themen immer etwas länger, weil ich die Artikel in der Regel mehrfach lesen muss. Werde ich mich die nächsten Tage dran setzten.
Danke hat geklappt in Bezug auf PresentationFramework
Hallo,
Leider ist mir für diesen Beitrag kein andere Titel eingefallen. Wie bereits aus meinen anderen Beiträgen ersichtlich beschäftige ich mich momentan mit der Integration von SQLlite in mein kleines Programm. Dazu bastel ich an eine Klasse für meine SQLite Operationen, die ich evtl. später auch für andere Projekte nutzen kann. Ähnlich wie bei der SQLite-net habe ich eine Methode, dass mir erlaubt aus Models Tabellen zu erstellen. Mich würde interessieren, wie die Profis unter Euch meine aktuelle Methode beurteilen und was ich evtl. verbessern könnte. Dabei geht es nicht direkt um die SQLite Funktion, der String der erzeugt wird macht als SQLite Befehl, das was er soll, sonder rein um den Weg zum String.
Meine Klasse für die Attribute:
class DbAttributes : Attribute
{
public bool IsPrimary { get; set; }
public bool IsAuto { get; set; }
public bool IsInteger { get; set; }
public bool IsText { get; set; }
}
Beispiel eines Models:
class User
{
[DbAttributes(IsPrimary =true, IsAuto =true, IsInteger =true)]
public long Id { get; set; }
[DbAttributes(IsText =true)]
public string Login { get; set; }
[DbAttributes(IsText = true)]
public string Firstname { get; set; }
[DbAttributes(IsText = true)]
public string Lastname { get; set; }
[DbAttributes(IsText = true)]
public string PersId { get; set; }
[DbAttributes(IsText = true)]
public string Password { get; set; }
[DbAttributes(IsInteger =true)]
public long Role { get; set; }
[DbAttributes(IsInteger = true)]
public long First { get; set; }
[DbAttributes(IsInteger = true)]
public long Active { get; set; }
}
Meine Methode:
private void createTable<T>()
{
PropertyInfo[] props = typeof(T).GetProperties();
string[] cols = new string[props.Count()];
for(int i = 0; i < props.Count(); i++)
{
string colString = String.Format("'{0}'", props[i].Name);
var attrs = props[i].GetCustomAttributes(true);
foreach (DbAttributes attr in attrs)
{
colString += (attr.IsInteger) ? " INTEGER" : "";
colString += (attr.IsText) ? " TEXT" : "";
colString += (attr.IsPrimary) ? " PRIMARY KEY" : "";
colString += (attr.IsAuto) ? " AUTOINCREMENT" : "";
}
cols[i] = colString;
}
string createTable = String.Format("CREATE TABLE IF NOT EXISTS '{0}' ({1});", typeof(T).Name, String.Join(", ", cols));
queryNon(createTable);
}
createTable<User>();
erzeugt dann folgenden String
CREATE TABLE IF NOT EXISTS 'User' ('Id' INTEGER PRIMARY KEY AUTOINCREMENT, 'Login' TEXT, 'Firstname' TEXT, 'Lastname' TEXT, 'PersId' TEXT, 'Password' TEXT, 'Role' INTEGER, 'First' INTEGER, 'Active' INTEGER);
Danke für die Tipps. Ich werde weiter versuchen mich zu belesen.
Unter Tools - Options - Environment - International Settings kannst du die Sprache umstellen.
Dort ist bereits English ausgewählt, wie gesagt die Oberfläche ist ja auch in Englisch nur komischerweise die Fehlermeldungen nicht.
Hallo,
ich nutze VS 2017 Community, mein Windows System läuft auf Deutsch, VS habe ich in Englisch installiert. Jetzt zeigt er mir aber die Fehlermeldungen trotzdem in Deutsch an. Im Netzt gibt es für ältere Versionen von VS den Tipp die .net Language Pakete zu deinstallieren. Aber unter Windows 10 und VS 2017 gibt es die wohl nicht mehr. Jedenfalls weder unter Windows "Programme deinstallieren" noch im Setup von VS.
Dan bekomme ich bei Fehlern, scheinbar nur wenn es SQLite betrifft die Meldung:
No Symbols Loaded: PresentationFramework.pdb not included. Bekomme dann auch nicht die Stelle im Code angezeigt, die den Fehler verursacht.
Also ich habe mich jetzt durch alle möglichen Beispiele gewühlt, die ich mit Hilfe von Google und den Suchbegriffen "c# wpf sqlite" gefunden habe und bin bisher kaum auf aussagekräftige Beispiele gestoßen, die sich stark von meinem zur Zeit verwendeten Code unterscheiden.
Wäre es evtl. möglich mir in Bezug auf "Verwende Dependency Injection und vermeide Magic Strings oder Hardcoded-Stuff wie DB-Namen." Beispiele in Bezug auf meinen Code aufzuzeigen?
Ja, das ist schon sehr unelegant. Im Falle des Klartext-Passwortes sogar fahrlässig.
- Schau Dir den Repository Pattern an.
- Speicher Passwörter niemals im Klartext, sondern gesalzen (
> )- Verwende Dependency Injection und vermeide Magic Strings oder Hardcoded-Stuff wie DB-Namen.
- Erstelle Datenbanken besser mit Bibliotheken wie FluentMigrator.
- Bei Sqlite würde ich auch Dapper als MicroORM empfehlen.
Passwörter: Meine MD5 Methode aus den Anwendungsbeispiel:
User login = sqlite.Login(Loginname, HelperClass.MD5Hash(Password));
versieht das Passwort mit einem Salt.
Der Rest der Punkte sind für mich ehrlich gesagt böhmische Dörfer 😉 Da werde ich mich wohl noch weiter einlesen müssen.
Ok. Leider sind die meisten ausführlichen Tutorials und Code Schnipsel, die ich im Netzt zum Thema WPF und SQLite gefunden habe in Zusammenhang mit dem EntityFramework 6.
Momentan habe ich meine SQLite Operationen in einer Helfer Klasse, aber irgendwie sieht das ganze für mich "unelegant" aus.
In meinem MainViewModel nutze ich das ganze so (Beispiele):
SQLiteHelper sqlite = new SQLiteHelper();
if (!sqlite.CheckAdmin())
{
[...]
}
User login = sqlite.Login(Loginname, HelperClass.MD5Hash(Password));
Und mein SQLite Klasse sieht so aus:
class SQLiteHelper
{
private SQLiteConnection sqlConn;
private static string sqliteFile = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "/resperLaMe.db"; // set folder for database
private static string sqlitePw = "dbpassword"; // set password for database
public SQLiteHelper()
{
// check if database file exist when not create with password
if (!File.Exists(sqliteFile))
{
sqlConn = new SQLiteConnection("Data Source=" + sqliteFile);
sqlConn.SetPassword(sqlitePw);
}
sqlConn = new SQLiteConnection("Data Source=" + sqliteFile + ";Password=" + sqlitePw); // connect to database
// create tables, when not exist
string query =
"CREATE TABLE IF NOT EXISTS user (id INTEGER PRIMARY KEY AUTOINCREMENT, 'login' TEXT, 'firstname' TEXT, 'lastname' TEXT, 'persid' TEXT, 'password' Text, 'role' INTEGER, 'first' INTEGER, 'active' INTEGER);" +
"CREATE TABLE IF NOT EXISTS userRights (id INTEGER PRIMARY KEY, 'lwe' INTEGER, 'lwa' INTEGER, 'lwb' INTEGER, 'lwi' INTEGER, 'mwe' INTEGER, 'mwa' INTEGER, 'mwb' INTEGER, 'mwi' INTEGER, 'vacc' INTEGER, 'vadr' INTEGER);" +
"CREATE TABLE IF NOT EXISTS admin ('password' Text);";
queryNon(query);
}
// check if admin password exist
public bool CheckAdmin()
{
sqlConn.Open();
var command = sqlConn.CreateCommand();
command.CommandText = "SELECT * FROM admin";
SQLiteDataReader reader = command.ExecuteReader();
bool rows = reader.HasRows;
sqlConn.Close();
return rows;
}
// login user
// if login doesnt match return an empty user
public User Login(string login, string pw)
{
User user = new User();
sqlConn.Open();
if (!login.Equals("Admin"))
{
var command = sqlConn.CreateCommand();
command.CommandText = "SELECT * FROM user LEFT JOIN userRights ON user.id = userRights.id WHERE user.login = '@login' AND user.password = '@password';";
command.Parameters.AddWithValue("@login", login);
command.Parameters.AddWithValue("@password", pw);
SQLiteDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
user.Id = reader.GetInt32(0);
user.Login = reader.GetString(1);
user.Role = reader.GetInt16(6);
break;
}
}
}
else
{
var command = sqlConn.CreateCommand();
command.CommandText = "SELECT * FROM admin WHERE admin.password = '@password'";
command.Parameters.AddWithValue("@password", pw);
SQLiteDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
user.Id = 0;
user.Login = "Admin";
user.Role = -1;
}
}
sqlConn.Close();
return user;
}
// methode for querys without response
private void queryNon(string query)
{
sqlConn.Open();
var command = sqlConn.CreateCommand();
command.CommandText = query;
command.ExecuteNonQuery();
sqlConn.Close();
}
}
Hallo,
ich versuche gerade EntityFramework 6 mit SQLite in meiner App zum Laufen zu bringen.
Ich habe dieses Tutorial als Grundlage genommen:
https://erazerbrecht.wordpress.com/2015/06/11/sqlite-entityframework-6-tutorial/
Ich bekomme aber einfach nicht bei New Connection SQLite zur Auswahl.
Ich habe die NuGetPakete installiert:
EntityFramework 6.1.3
System.Data.SQLite 1.0.105.1
System.Data.SQLite.Core 1.0.105.1
System.Data.SQLite.EF6 1.0.105.1
System.Data.SQLite.Linq 1.0.105.1
Ich habe das Paket von SQL herunter geladen:
sqlite-netFx451-setup-bundle-x86-2013-1.0.105.1.exe
und das Target Frameworka auf 4.5.1 gesetzt.
Ich weiß leider nicht, was ich übersehe.
Also ich habe jetzt das ganze mit UserControls umgesetzt.
In meiner MainWindow.xaml für jede Unterseite:
<DataTemplate DataType="{x:Type local2:StartPageViewModel}">
<local1:StartPage/>
</DataTemplate>
der Bereich ContentControl:
<ContentControl x:Name="Pages" DockPanel.Dock="Right" Content="{Binding SelectedViewModel}"/>
MainWindowsViewModel.cs hinzugefügt:
private object selectedViewModel;
public object SelectedViewModel
{
get { return selectedViewModel; }
set { selectedViewModel = value; OnPropertyChanged("SelectedViewModel"); }
}
mit
SelectedViewModel = new StartPageViewModel();
kann ich jetzt den Contentbereich steuern.
Für den ContentBereich habe ich jetzt für jede Unterseite eine xaml und cs Datei und ein ViewModel.
z.B.:
StartPage.xaml
<StackPanel>
<Label Content="Test Seite" />
<Button Content="Andere Seite" Command="{Binding CommandAnotherPage}"/>
</StackPanel>
StartPage.xaml.cs
public partial class StartPage : UserControl
{
public StartPage()
{
InitializeComponent();
}
}
StartPageViewModel.cs
public ICommand CommandSaveAdminPw { get; set; }
public StartPageViewModel()
{
CommandAnotherPage= new RelayCommand(parameter => anotherPage());
}
private void anotherPage()
{
}
Wie bekomme ich es jetzt hin, den Contentbereich aus dem StartPageViewModel heraus zu wechseln?
Wie bekomme ich von meinem StartPageViewModel heraus Zugriff auf zum Beispiel auf die LoginId (siehe Code Startbeitrag) in dem MainWindowsViewModel?
EDIT
Ok, das mit den Daten übergeben kann ich ja einfach mit
SelectedViewModel = new StartPageViewModel(LoginId);
machen oder?
Den Content durch einen Button im Content ändern, habe ich jetzt mit folgendem Bindig gelöst:
<Button Content="Home" Command="{Binding Path=DataContext.CommandStartView, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
Jetzt versuche ich es noch hinzubekommen, dieses aus dem Programmcode herraus hin zu bekommen.
Danke für den Tipp. Ich suche mal nach Beispielen im Netz.
Hallo,
wenn ich ein Programm ähnlich wie auf dem Bild, was ich am Ende des Posts angefügt habe umsetzen möchte, wie gehe ich am besten vor?
Ich habe das MainWindow, welches mein MainViewModel nutzt. In der XAML Datei habe ich jetzt Buttons, die den Inhalt des Hauptbereiches verändern sollen.
Um beim Beispiel der Auftrags und Lagerverwaltung zu bleiben: z.B. eine Liste der Bestellungen, eine Liste der Kunden, eine Liste der Lieferanten.
In meinem ersten Versuch ohne MVVM habe ich das ganze über einen Frame gelöst, was sich aber bei Nutzung des MVVM Prinzips als nicht mehr ganz so einfach heraus stellt.
Der Contentbereich soll mit dem MainViewModel kommunizieren können, weil dort auch Login und Logout verwaltet wird und jeder Nutzer hat eigene Daten.
Hatte schon überlegt ob ich alles Inhalte in das Main Windows packe und dann durch die Buttons die Visibility ändere, was aber ein sich nicht sehr Elegant sein dürfte. Welchen Weg würdet ihr gehen?
Meine Inhalte in etwas gekürzter Version:
MainWindow.xaml
<DockPanel>
<StackPanel DockPanel.Dock="Left">
<Label Content="[res][per]" />
<Button>
Bestellung
</Button>
<Button>
Lieferanten
</Button>
</StackPanel>
<DockPanel DockPanel.Dock="Top">
<Label Content="Programm Titel" DockPanel.Dock="Left"/>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Right" HorizontalAlignment="Right">
<Label Content="Eingeloggt als:" />
<Label Content="{Binding LoginName}" />
<Button Content="Logout" Command="{Binding CommandLogout}" />
</StackPanel>
</DockPanel>
<!-- HIER SOLL DER CONTENT HIN -->
</DockPanel>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
}
MainWindowViewModel.cs
using resperLaMa.Commands;
using resperLaMa.Connections;
using resperLaMa.Helper;
using resperLaMa.Models;
using resperLaMa.Pages;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace resperLaMa.ViewModels
{
class MainWindowViewModel : BaseViewModel
{
private string loginName;
private int loginId;
public string LoginName
{
get { return loginName; }
set
{
loginName = value;
OnPropertyChanged("LoginName");
}
}
public int LoginId
{
get { return loginId; }
set
{
loginId = value;
OnPropertyChanged("LoginId");
}
}
public ICommand CommandLogout { get; set; }
public MainWindowViewModel()
{
CommandLogout = new RelayCommand(parameter => SendLogOut());
}
public void SendLogOut()
{
LoginId = -1;
}
}
}
Erstes Suchergebnis bei Google:
>
War auch drauf gestoßen, aber da der Beitrag älter als 7 Jahre ist und es dort heisst, dass man dafür das MVVM Prinzip aufbrechen soll, hatte ich gedacht, dass es evtl. mittlerweile einen anderen Lösungsansatz gibt.
In der Datenbank befindet sich doch gar nicht das Kennwort, sondern der gesalzte Hash vom Kennwort. Also braucht man das Kennwort auch nicht, sondern den gesalzten Hash davon zum Vergleichen. 😉
Stimmt, aber trotzdem muss ich ja erstmal das Passwort aus der PasswordBox in meine Hashfunktion bringen.
Hallo,
bei meinem Programm muss sich der Nutzer einloggen.
Dazu hat er einen Login-Namen und ein Passwort.
Wenn er sich einloggen will, soll Login und Passwort mit der lokalen Datenbank abgeglichen werden.
Jetzt kann man ja eine PasswordBox nicht mit einem Binding versehen, wie realisiert man das ganze anders?
Ich versuche mich gerade in das MVVM Prinzip einzuarbeiten.
Was ich nicht ganz verstehe (ich habe mir die Dateien runtergeladen), ist, dass ich in deinem Beispiel erst die Mitarbeiter in ein Model lade und dann in das Viewmodel. Wenn ich die Daten zum Beispiel aus einer Datenbank lade, könnt eich sie doch direkt in das Viewmodel laden oder?
Zu meinem P.S. ist wohl zu sagen, dass ich das als komplett eigene Version veröffentlichen werde, also als eigenes Programm, das eine eigenen Lösung zum Speichern der Daten nutz (vermutlich SQLite), da es einige Interessent gibt, die die Software auf "isolierten" Rechner ausführen möchten.
Ich habe jetzt gerade gelesen, das bei Cirtix XenApps auf dem Server grundsätzlich auch ein SQL Server installiert wird, was sich ja dann anbieten würde.
Hallo,
kurz vorweg, bisher habe ich nur Erfahrung mit MySQL / SQLite (PHP, Java).
Ich arbeite zur Zeit an einer Software in der Art einer Lagerverwaltung.
Die Daten sollen in einer zentralen Datenbank gespeichert werden, auf die Rechner von mehreren Standorten zugreifen können (auch Zeitgleich) bzw. soll die Software später auch auf Windows Terminal Server kompatibel sein (u.a. Citrix) wo der Client auf einem Rechner mehrfach gestartet wird.
Zuerst habe ich an eine Lösung gedacht, wo die Datenbanken zentral auf meinem Server liegen, aber ich denke, dass die meiste Kunden die Datenbanken in Ihrem eigenen System haben möchten.
Ich bin nun unschlüssig was ich nutzen soll.
P.S. Es sol auch eine Stand Alone Version der Software geben, die die Datenbank nur auf dem lokalen Rechner speichert.
Auf meiner Suche bin ich jetzt auf PDFsharp & MigraDoc gestoßen und muss sagen, es funktioniert sehr gut damit.
Hallo,
ich möchte gerne aus meiner Anwendung heraus drucken. Dabei ist es wichtig, dass ich die Abmessungen wie Seitenränder und Abstände genau bestimmen kann, da ich unter anderem Etiketten drucken möchte.
Bisher habe ich nur diesen Ansatz gefunden: http://stackoverflow.com/questions/29892177/print-dialog-and-print-prewiew-dialog-for-wpf
Also in der Seitenstruktur ein Flowdocument nutzen, dieses als xps speichern und dann die Datei mit einem PrintDialog aufrufen.
Wirkt für mich sehr umständlich. Gibt es noch andere Möglichkeiten?
Mit dem MVVM hardere ich noch. Versuche es bei einem anderen Projekt umzusetzen, aber bin da etwas begriffsstutzig.
Habe schon mithilfe des Tutorial hier im Forum und aus meinem Buch (C# mit Visual Studio 2015) dran gebastelt. Aber klappt noch nicht so alles wie ich das will und verstehe auch einige Zusammenhänge nicht bzw. finde es teilweise für mein kleines Projekt zu umfangreich.
Ich finde keine Fehlermeldung im Ausgabefenster. Da erscheint nur die Meldung des
Console.WriteLine(user.Lastname);
den ich nach
user = MainWindow.sqlHelper.NewUser(Firstname.Text, Lastname.Text);
eingefügt habe.
Hallo,
irgendwie sehe ich gerade den Wald vor lauter Bäumen nicht.
Also wenn ich in der cs Datei die Save_Click Aktion auslöse, wird das Obejkt user mit neuen Daten aktualisiert (funktioniert und getestet mithilfe von "Console.WriteLine(user.Lastname)". Aber der Content der Label bleibt leer und aktualisiert sich nicht. Was habe ich vergessen?
<Grid Style="{StaticResource FormGrid}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Vorname:"/>
<Label Grid.Row="0" Grid.Column="1" Content="{Binding Firstname}"/>
<Label Grid.Row="1" Grid.Column="0" Content="Nachname:"/>
<Label Grid.Row="1" Grid.Column="1" Content="{Binding Lastname}"/>
</Grid>
In der cs Datei (gekürzt):
namespace resper.LaMa.Pages.Admin
{
public partial class NewAccount : Page
{
UserModel user;
public NewAccount()
{
InitializeComponent();
this.DataContext = user;
}
private void Save_Click(object sender, RoutedEventArgs e)
{
user = MainWindow.sqlHelper.NewUser(Firstname.Text, Lastname.Text);
}
}
}
Das UserModel sieht so aus (gekürzt):
public class UserModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _Firstname;
public string Firstname
{
get { return _Firstname; }
set
{
if (_Firstname != null && !_Firstname.Equals(value))
{
IsDirty = true;
}
_Firstname = value;
OnPropertyChanged("Firstname");
}
}
private string _Lastname;
public string Lastname
{
get { return _Lastname; }
set
{
if(_Lastname != null && !_Lastname.Equals(value))
{
IsDirty = true;
}
_Lastname = value;
OnPropertyChanged("Lastname");
}
}
public UserModel() { }
private void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Das mit dem Edit hatte ich mir auch schon überlegt, werde es mal probieren mit den beiden Vorschlägen. Danke für die Tipps
Ja mit dem MVVM Artikel habe ich mich auch schon versucht auseinanderzusetzen, habe auch schon versucht mich mit Hilfe eines Buches (https://www.rheinwerk-verlag.de/c-6-mit-visual-studio-2015_3819/) schlau zu machen aber irgendwie fehlen mir da wohl noch ein paar Grundlagen.
Ok, also ich habe es jetzt ein bsichen geändert.
XAML:
<StackPanel Orientation="Vertical">
<Label Content="Nutzer Details" Style="{StaticResource CardTitle}" />
<Grid Style="{StaticResource FormGrid}" DataContext="{Binding SelectedItem, ElementName=UserList}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Content="Vorname:" Grid.Row="0" Grid.Column="0" />
<Label Content="Nachname:" Grid.Row="1" Grid.Column="0" />
<Label Content="Personal ID:" Grid.Row="2" Grid.Column="0" />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Firstname}" />
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Lastname}" />
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding PersId}" />
</Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="CancleEdit" Content="Abbrechen" Margin="10,0"/>
<Button x:Name="SaveEdit" Content="Speichern" />
</StackPanel>
</StackPanel>
Code Behind:
AdminModel admin = new AdminModel()
{
UserList = MainWindow.sqlHelper.GetAllUser()
};
UserList.DataContext = admin.UserList;
Im Admin Model sieht das jetzt so aus:
namespace resper.LaMa.Models
{
public class AdminModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private List<UserModel> _UserList;
public List<UserModel> UserList
{
get { return _UserList; }
set
{
_UserList = value;
OnPropertyChanged("UserList");
}
}
private void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
}
In der SqlHelper sieht das ganze so aus:
public List<UserModel> GetAllUser()
{
List<UserModel> allUser = new List<UserModel>();
SQLiteDataReader sdr = Query("SELECT * FROM user");
while (sdr.Read())
{
allUser.Add(new UserModel(sdr));
}
return allUser;
}
Ziel ist es jetzt, dass wenn der Anwender einen anderen Eintrag auswählt, zu prüfen ob der vorherige Eintrag geändert wurde und per Popup zu fragen ob die Änderung gespeichert werden soll wenn er nicht vorher den Speicher Button gedrückt hat
Hallo,
Also ich habe ein ListView Element mit einem Formular verknüpft.
Ich möchte nun, dass wenn der Nutzer einen anderen Eintrag auswählt geprüft wird ob im Formular was geändert wurde und wenn ja, gefragt wird ob die Änderung gespeichert werden soll.
In meiner XAML sieht das momentan so aus:
<ListView Name="UserList" ItemsSource="{Binding Mode=OneWay}" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding Id}" />
<GridViewColumn Header="Nachname" DisplayMemberBinding="{Binding Lastname}" />
<GridViewColumn Header="Vorname" DisplayMemberBinding="{Binding Firstname}" />
<GridViewColumn Header="Personal ID" DisplayMemberBinding="{Binding PersId}" />
<GridViewColumn Header="Login" DisplayMemberBinding="{Binding Login}" />
</GridView>
</ListView.View>
</ListView>
<Border Style="{StaticResource CardMarginTop}" Grid.Column="0" Grid.Row="1">
<StackPanel Orientation="Vertical">
<Label Content="Nutzer Details" Style="{StaticResource CardTitle}" />
<Grid Style="{StaticResource FormGrid}" DataContext="{Binding SelectedItem, ElementName=UserList}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Content="Vorname:" Grid.Row="0" Grid.Column="0" />
<Label Content="Nachname:" Grid.Row="1" Grid.Column="0" />
<Label Content="Personal ID:" Grid.Row="2" Grid.Column="0" />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Firstname}"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Lastname}"/>
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding PersId}"/>
</Grid>
</StackPanel>
</Border>
Code behind:
public partial class ManageAccounts : Page
{
public ManageAccounts()
{
InitializeComponent();
List<UserModel> userList = MainWindow.sqlHelper.GetAllUser();
UserList.DataContext = userList;
}
}
Danke für Eure Tipps.
Außerdem hab ich meistens mehrere Resourcen-Dateien, z.B. Styles.xaml, Icons.xaml, Templates.xaml usw.
Daran habe ich auch schon gedacht und grübel noch über eine Struktur nach.
Ansonsten würde sich mein Code von deinem noch dadurch unterschieden, daß ich Commands statt Events verwende, wegen MVVM
Werde ich mir mal zu Gemüte führen.
Dazu gehören z.B. auch Farben etc.
Werde ich nachholen.
Zwei weitere Fragen:
Warum kann ich eigentlich beim Textblock in der Resourcendatei kein Border Effekt hinzufügen, hätte gerne den Teil mit dem Border Effect ausgelagert.
Meine Buttons für die linke Seite sehen ja so aus:
<Button x:Name="ManageAccounts" Click="ManageAccounts_Click" Style="{StaticResource MenuButton}">
<StackPanel Orientation="Vertical">
<TextBlock Text="" HorizontalAlignment="Center" Style="{StaticResource IconFont}"/>
<TextBlock Text="Nutzerverwaltung" HorizontalAlignment="Center" Margin="0,5,0,0"/>
</StackPanel>
</Button>
Kann ich in der Resource Datei die beiden TextBlock Elemente in der Button Definition mitgestalten?
<Style TargetType="{x:Type Button}" x:Key="MenuButton">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="#c3cee0" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="0,0,0,0.5" BorderBrush="#c3cee0" Background="{TemplateBinding Background}" Padding="0,20">
<Grid>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#333333"/>
<Setter Property="Foreground" Value="#EF3F3F" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Hallo,
mal eine Frage von einem Anfänger an die erfahrenden User:
Was alles an Styles lagert Ihr in die ResourceDictionarys aus?
Der Codeblock ist meine Hauptseite, ich habe bisher nur die Menü Buttons und die Icon Buttons ausgelagert, weil dieses wiederkehrende Elemente sind.
Wie würde das bei Euch aussehen?
<Window x:Class="resper.LaMeMa.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:resper.LaMeMa"
mc:Ignorable="d"
Title="[res][per] Lager- und Medikamentenverwaltung"
WindowStartupLocation="CenterScreen" WindowState="Maximized">
<DockPanel Background="#eef1f5">
<StackPanel DockPanel.Dock="Left" Orientation="Vertical" Background="#3D3D3D" Width="200">
<Border BorderBrush="#FFFFFF" BorderThickness="0" VerticalAlignment="Top" Background="#EF3F3F" Height="70">
<Border.Effect>
<DropShadowEffect BlurRadius="10" ShadowDepth="1" Color="#323232" Direction="0" Opacity="0.2" />
</Border.Effect>
<TextBlock Text="[res][per]" Foreground="#FFFFFF" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="30"/>
</Border>
<Button x:Name="ManageAccounts" Style="{StaticResource MenuButton}" Click="ManageAccounts_Click">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="" Style="{StaticResource IconFont}" HorizontalAlignment="Center"/>
<TextBlock Text="Nutzerverwaltung" HorizontalAlignment="Center" Margin="0,5,0,0"/>
</StackPanel>
</Button>
</StackPanel>
<Border DockPanel.Dock="Top" BorderBrush="#FFFFFF" BorderThickness="0" VerticalAlignment="Top">
<Border.Effect>
<DropShadowEffect BlurRadius="10" ShadowDepth="1" Color="#323232" Direction="0" Opacity="0.2" />
</Border.Effect>
<DockPanel Background="#FFFFFF" Height="70">
<TextBlock DockPanel.Dock="Left" Text="Lager- und Medikamentenmanager" VerticalAlignment="Center" Margin="20" Foreground="#666666" FontSize="18"/>
<Button x:Name="LogoutButton" DockPanel.Dock="Right" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,10,0" Style="{StaticResource IconButton}" Visibility="Collapsed" Click="LogoutButton_Click">
<TextBlock Text="" Style="{StaticResource IconFont}" />
</Button>
<TextBlock DockPanel.Dock="Right" x:Name="MenuLoginName" Text="Bitte einloggen" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,10,0" Style="{StaticResource MenuTitle}"/>
</DockPanel>
</Border>
<Frame x:Name="MainFrame" Source="Accounts/LoginPage.xaml" NavigationUIVisibility="Hidden" Padding="20">
</Frame>
</DockPanel>
</Window>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:resper.LaMeMa.ResourceDictionaries">
<Style TargetType="{x:Type Button}" x:Key="MenuButton">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="#c3cee0" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="0,0,0,0.5" BorderBrush="#c3cee0" Background="{TemplateBinding Background}" Padding="0,20">
<Grid>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#333333"/>
<Setter Property="Foreground" Value="#EF3F3F" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type Button}" x:Key="MenuButtonSelected">
<Setter Property="Background" Value="#333333" />
<Setter Property="Foreground" Value="#EF3F3F" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="0,0,0,0.5" BorderBrush="#c3cee0" Background="{TemplateBinding Background}" Padding="0,20">
<Grid>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type Button}" x:Key="IconButton">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="#666666" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="0" Background="{TemplateBinding Background}">
<Grid>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TextBlock}" x:Key="IconFont">
<Setter Property="TextElement.FontFamily" Value="pack://application:,,,/fonts/#FontAwesome" />
<Setter Property="FontSize" Value="25" />
</Style>
</ResourceDictionary>
Welchen Nutzen hat das Ganze?
Eigentlich ist WPF meines Wissens nach einheitlich in der Darstellung.
Unterschiede zu Windows 7 dürften hier eigentlich keine bestehen.
Das Problem dürften eher unterschiedliche Auflösungen werden, die dann zu Darstellungsfehlern führen können.Ansonsten solltest du dir eine Windows 7 Lizenz und dann eine VM aufsetzen bzw. eine Zweitinstallation neben deinem aktuellen Windows einrichten.
Dann kannst du sowas selbst prüfen.
Aber gerade XAML soll ja die Darstellung durch eine einheitliche Darstellung überall gleich darstellen.T-Virus
Also bei stackoverflow.com gibt es einige Beiträge, die davon berichten, dass es Probleme gibt mit unterschiedlichen Darstellungen der Optik zwischen Win 10 und Win 7.
Da ich in meinem Programm völlig auf die Standard Windows Optik verzichten möchte und die Optik einer Web GUI simuliere, hatte ich in die Richtung Befürchtungen.
Ich werde mal einen alten Laptop rauskramen und da Windows 7 drauf machen, ein paar alte Lizenzen habe ich ja noch.
Hallo,
ich bin relativ neu in der Welt von WPF, C# und XAML. Bisher habe ich Erfahrungen mit Java, PHP, JS und Swift.
Ich nutze Windows 10 mit Visual Studio 2017. Gibt es irgendeine Möglichkeit Windows 7 zu simulieren, wie zum Beispiel beim Android Emulator, wo ich die jeweilige Version auswählen kann?
Gruß
Markus