sieht sehr gut aus 👍
Ich hätte aber noch ein paar Verbesserungsvorschläge:
-wenn ich eine neue Aufgabe einfüge, ist die neue Zeile nur halb gehighlightened.
Was ich auch unschön finde ist die Vermischung von englischem und deutschen Text.
Dass Enddatum einer Aufgabe darf kleiner sein als das Startdatum ?
ein löschen-button bei den Prioritäten wäre ganz nett
Wie kann ich Anhänge anschauen / einzeln löschen? (ok habs rausgefunden, hat aber ein wenig gedauert *g)
auf einmal waren alle aufgaben, die ich eingetragen waren weg (bis auf einen). beim beenden und neu laden des Projektes waren sie aber wieder drin. weiß aber leider net wie ich es geschafft habe ...
wenn ich einen status erstelle und einer Aufgabe diesen Status zuweise und ich lösce den status dann wieder, dann ist der Status direkt auf erledigt. Besser wärs meiner Meinung den Status leer zu lassen und ne Fehlermeldung (in form eines roten Rahmens, Ausrufezeichen, ...) anzuzeigen
bei der priorität das gleiche wie oben.
Im Setter von
public double dDNumthree
wird der value Parameter nicht verwendet. Das kann zwar gewollt sein, ist es aber in 99.999% der Fälle nicht.
und ich glaube nicht dass er zu den 0,001 % gehört 😃 folgendes sollte ausreichend sein:
public double dDNumthree
{
get
{
return DNumone + DNumtwo;
}
}
dann kann man
public double result()
{
return dDNumthree;
}
noch löschen, denn die braucht man nicht.
Ausserdem kannst du anstatt ne private Variable zu erstellen und diese dann zu kapseln doch direkt die "normalen" Properties verwenden. "Aufgeräumt" würde der Code dan so aussehen:
public double dDNumOne { get; set }
public double dDNumTwo { get; set }
public double dDNumThree { get { return dDNumOne + dDNumTwo; }
public double Add(double value1, double value2)
{
return value1 + value2;
}
}
ist aber alles etwas unschön, ich würde die properties ganz weglassen ... und nur die add() Methode anbieten.
MfG TripleX
das u.a. Aussehen der Textbox festlegt.
Dafür gibt es in WPF doch styles
Aber das DataContext erlaubt doch nur ein Object als Quelle
Er meinte das anders, und zwar gib der TextBox einen Namen (z.B. txtInput), dann kannst du im code behind darauf zugreifen mittels txtInput.Text = "Hello World". Oder um eine Datenbindung im CodeBehind zu erstellen, kannst du dann acuh folgendes machen:
Binding binding = new Binding();
binding.Source = Zaehler;
txtInput.SetBinding(TextBlock.TextProperty, binding);
Und mit MVVMPatterns habe ich mich nie beschäftigt.
Solltest du mal tun, ist en ganz nettes Pattern für WPF-Anwendungen
btw, ich würde dir empfehlen, Properties groß zu schreiben (ist nämlich Standard in C#):
public string InfoText
{
get { return _infoText; }
set
{
_infoText = value;
OnPropertyChanged("InfoText");
}
}
MfG TripleX
ich verstehe nicht was dich daran hindert, im Konstruktors des CodeBehinds folgendes zu schreiben:
DataContext = this;
?
MfG TripleX
Das was talla schon sagt beschreibt dein Problem ... wenn du immer mit dem gleichen Object arbeitest ändern sich auch die Werte in der Liste. Du könntest jetzt um das verhalten vorzubeugen das gewünschte Object wie folgt klonen:
int[] co = { 1, 2, 3, 4 };
int[] co2 = (int[])co.Clone();
test.Add(co);
for (int i = 0; i < co2.Length; i++)
{
co2[i] = i + 10;
}
test.Add(co2);
habe es jetzt so gelöst, obwohl ich die lsg. irgendwie nicht schön finde!
ih finde den Quellcode auch sehr unschön mit den ganzen if-bedingungen und for-schleifen. Kannst du keine Teile auslagern in eine extra Funktion? Oder speicher, um den code etwas lesbarer zu machen wenigstens folgende Variable zwischen:
gv.Lastfall[LFNr].schrittNummer[schrittNummer].Stuetzen
also ich würde ganz oben über der erste forschleife schreiben:
var guterName = gv.Lastfall[LFNr].schrittNummer[schrittNummer].Stuetzen
var und guterName sollten natürlich durch etwas sinnvolles ersetzt werden.
Die Schleifen können problemlos in einer beliebigen Reihenfolge fertig werden, jedoch soll url1 immer vor url2 im Thread aufgerufen werden und nicht umgedreht:
Also du hast in deinem jetzigen post eine schleife und in dieser schleife erstellst du einen Thread der eine Methode aufruft. Diese Methode wird sequentiell vom Thread abgearbeitet, dass heißt getHTML(1) wird vor getHTML(2) aufgerufen.
Ich glaube in deiner vorherigen Lösung war es andersherum - da hattest du eine schleife wo du einen Thread erstellt hast welche dann die gethtml(i) (wobei i in der schleife jedesmal variiert). Das heißt du erzeugst einen Thread für getHTML(1) und direkt danach einen Thread getHTML(2). Da wird das nix mit sequenzielle Abarbeitung dank deinem Betriebssystem 😉
€dit: Sry hab falsch geschaut, in deiner letzten Lösung hattest ja die selbe Schleife.
Hm dann könnte es meiner Meinung nur noch dran liegen dass du in den getHTML Methoden wiederrum einen Thread startest, der dir zum Beispiel den Quellcode holt. Dann wird die zweite GETHML anweisung aufgerufen welche schneller fertig ist als die erste?
dann bist da aber den falschen Weg gegangen. In der Schleife erstellt du immer wieder einen neuen Thread, und welcher Thread von den ganzen nun zuerst fertig wird bzw abgearbeitet wird ist unterschiedlich.
Wenn du willst dass zwar mehrere Schleifen parallel abgearbeitet werden, die schleife jedoch sequentiell dann erstelle einen Thread für jede schleife.
Der Thread ruft dann eine Methode auf, wo die Schleife drin ist. Das lässt sich ganz gut mit Anonymen Methoden lösen. Dazu mal ein kurzes Beispiel:
Thread[] thrd = new Thread[2];
for (int i = 0; i < thrd.Length; i++)
{
thrd[i] = new Thread(new ThreadStart(() => {
for(int j = 0; j < 1000; j++) {
Console.WriteLine(Thread.CurrentThread.Name + " ... " +j);
}
}));
thrd[i].Name = "Thread "+i;
thrd[i].Start();
}
MfG TripleX
ich würde den Pfad folgendermaßen aufbauen:
String sExe = Path.Combine(Application.StartupPath , "Ordner/Ordner/Ordner/start.exe")
Wozu nimmst die Path.Combine Methode wenn du sie nicht ganz ausschöpfst?
Besser wäre es folgendermaßen:
Path.Combine(Application.StartupPath, "Ordner", "Ordner", Ordner", "start.exe")
MfG TripleX
...und lies ihn dann über Match.Groups[1] aus.
magic numbers X(
besser ist folgendes:
(?<Name>(*.?))
Dann kann man mittels Match.Groups["Name"].Value auf den Wert zugreifen 😉
Vielen Dank für deinen tollen Artikel, hab wieder einiges gelernt. 👍
Ich werde jetzt auch noch etwas zu deinem Artikel beitragen, denn ich denke dass das ganz gut hier herein passt:
Es kommt oft vor, dass eine Property von einer anderen abhängig ist. Wenn man also die eine Property ändert, ändert sich automatisch eine andere Property. Am besten ich zeige mal ein kurzes Beispiel:
public class TestClass : INotifyPropertyChanged
{
private int _width;
private int _height;
public int Height
{
get { return _height; }
set { _height = value; NotifyPropertyChanged(MethodInfo.GetCurrentMethod()); }
}
public int Width
{
get { return _width; }
set { _width = value; NotifyPropertyChanged(MethodInfo.GetCurrentMethod()); }
}
public int Area
{
get { return Height * Width; }
}
Wie man erkennen kann ist Area von _Height _und _Width _abhängig. Also eigentlich müsste man, sobald man _Width _geändert, bekanntgegeben werden dass sich _Area _geändert hat. Ich habe mich demletzt mit diesem Problem auseinander gesetzt und bin dabei auf 2 Lösungen gekommen:
1. Die einfache Variante:
Man ändert die Setter der jeweiligen Properties folgendermaßen um:
public int Height
{
get { return _height; }
set
{
_height = value;
NotifyPropertyChanged(MethodInfo.GetCurrentMethod());
NotifyPropertyChanged("Area");
}
}
public int Width
{
get { return _width; }
set
{
_width = value;
NotifyPropertyChanged(MethodInfo.GetCurrentMethod());
NotifyPropertyChanged("Area");
}
}
public int Area
{
get { return Height * Width; }
}
Also sobald sich _Width _oder _Height _ändert, wird auch bekanntgegeben dass _Area _sich geändert hat.
Dass Problem bzw. unschöne an dieser Variante ist meiner Meinung jedoch, dass _Width _ eigentlich gar nichts von Area wissen sollte. Denn wenn wir aus irgendeinem Grund die Area nicht mehr brauchen und entfernen würden, dann sollten wir den Aufruf der NotifypropertyChanged() aus _Width _und Height auch entfernen (was man leicht vergessen kann). Außrdem kann es vorkommen, dass man mehrere Properties hat, welche von _Width _abhängig sind, und dann würden wir den setter nur unnötig aufblasen.
2. Die schönere Variante (mittels Attribute):
Die Nachteile aus Variante 1 löst man, indem man Attribute verwendet. Ich zeige euch mal einen Codeausschnitt, der das gleiche Ziel wie in Variante 1 verfolgt:
public int Height
{
get { return _height; }
set { _height = value; NotifyPropertyChanged(MethodInfo.GetCurrentMethod()); }
}
public int Width
{
get { return _width; }
set { _width = value; NotifyPropertyChanged(MethodInfo.GetCurrentMethod()); }
}
[DependsUpon("Height", "Width")]
public int Area
{
get { return Height * Width; }
}
Wie man erkennen kann hat _Area _jetzt ein Attribut erhalten. Mittels _DependsUpon _wird jetzt gesagt, dass Area von _Width _und Height abhängig ist. Sobald sich _Width _oder _Height _ändert wird automatisch auch das Event für _Area _gefeuert. Da dass aber nicht automatisch passiert brauchen wir noch ein wenig mehr Code. Hier ist ersmal der Code für das Attribut:
[global::System.AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
sealed class DependsUponAttribute : Attribute
{
#region Private Members
private readonly string[] _properties;
#endregion
#region Public Properties
public string[] Properties
{
get { return _properties; }
}
#endregion
#region Constructors
public DependsUponAttribute(params string[] properties)
{
this._properties = properties;
}
#endregion
}
Und hier ist die gesamt Klasse für das obige Beispiel:
public class TestClass : INotifyPropertyChanged
{
private Dictionary<string, string[]> _propertyDependencies;
private int _width;
private int _height;
public int Height
{
get { return _height; }
set { _height = value; NotifyPropertyChanged(MethodInfo.GetCurrentMethod()); }
}
public int Width
{
get { return _width; }
set { _width = value; NotifyPropertyChanged(MethodInfo.GetCurrentMethod()); }
}
[DependsUpon("Height", "Width")]
public int Area
{
get { return Height * Width; }
}
public TestClass()
{
#region Save depend Properties in the dictionary
_propertyDependencies = new Dictionary<string, string[]>();
foreach (var item in this.GetType().GetProperties())
{
var query = (from prop in this.GetType().GetProperties()
where prop.GetCustomAttributes(typeof(DependsUponAttribute), false)
.Cast<DependsUponAttribute>()
.Any((x) => x.Properties.Any((y) => y == item.Name))
select prop.Name).ToArray<string>();
if (query.Count() > 0)
{
_propertyDependencies.Add(item.Name, query);
}
}
#endregion
}
#region INotifyPropertyChanged Implementation (+ Notify Dependend Properties)
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#region Notify other Properties
if(_propertyDependencies.ContainsKey(propertyName))
{
string[] depended = _propertyDependencies[propertyName];
foreach (var propName in depended) NotifyPropertyChanged(propName);
}
#endregion
}
public void NotifyPropertyChanged(System.Reflection.MethodBase methodBase)
{
NotifyPropertyChanged(methodBase.Name.Substring(4));
}
#endregion
}
Im Konstruktor der Klasse werden die Abhängigkeiten der Properties untereinander ermittelt und in eine Dictionary abgespeichert.
Sobald sich jetzt eine Property ändert, wird in NotifyPropertyChanged ersteinmal das event abgefeuert und danach wird in der Dictionary geschaut, ob für das Properties Abhängigkeiten bestehen und für jene wird dann auch eine Benachrichtigung gesendet.
Fazit:
MfG TripleX
natürlich kannst du auf die Elemente zugreifen, du kannst ja z.B. mittels textBoxStart.Text = "Dummy" irgendeinen Text festlegen. Also ich verstehe nicht ganz wo du drauf hinaus willst.
Btw ich denke mal, dass du in den TabPages nicht nur eine TextBox anzeigen lassen willst, sondern es werden bestimmt mehrere Objekte sein, du du pro TabPage anzeigen lassen willst. Dann würde ich an deiner Stelle ein neues UserControl erstellen welches dann so aussehen soll wie du es willst. Dieses UserControl musst du dann nur noch später in ein Tab hinzufügen und kannst über Properties (welche du vorher natürlich implementiert haben musst) das verhalten bzw. Aussehen des UserControls beeinflussen.
MfG TripleX
Hallo Fiech,
also wenn ich dich richtig verstanden habe, weisst du erst ab Programmstart wieviele Netzwerkkarten im PC eingebaut sind (klingt logisch 😉 ). Jetzt möchtest du jenachdem wieviele Netzwerkkarten vorhanden sind, TextBoxen anzeigen lassen.
Nun also du könntest zum Beispiel sobald du eine Netzwerkkarte gefunden hast, mittels ParentControl.Controls.Add() eine neue TextBox hinzufügen. ParentControl ist das Control, wo deine TextBoxen angezeigt werden, z.B. eine GroupBox.
MfG TripleX
verwendetes Datenbanksystem: Sql Server Compact Edition 3.5
verwendetes Programmierumgebung: Visual Studio 2010 Beta 2
Hallo Gemeinde,
Ich habe seit kurzem die UnitTests für mich entdeckt und wollte damit jetzt ein paar meiner Klassen testen. Dazu wollte ich den UnitTest mit einer Datenbank verbinden, damit er die Werte, welche erz um Testen benötigt, aus einer Datenbank holt. Ich hätte nicht gedacht dass ich mich mehrere Stunden rumärgern und rumprobieren darf - bis dass ganze (nicht ...) funktioniert.
Also hier ist mal eine kure Beschreibung was ich bisher gemacht habe:
[TestMethod()]
[DataSource(@"Provider=System.Data.SqlServerCe.3.5;Data Source=(pfad)\TestDatabase.sdf"
, "LengthValidationTest")]
public void MaxLengthTest() //..
Wenn ich jetzt den Test starten bringt mir VS eine Fehlermeldung:
The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (
> ) in the MSDN Library.
Error details: The 'System.Data.SqlServerCe.3.5' provider is not registered on the local machine.
Ich habe jetzt schon die ganze Zeit rumprobiert, doch es will einfach nicht funktionieren. Im Netz habe ich bereits auch mehrfach nach einer Lösung gesucht doch ich konnte nichts verwertbares finden.
Kann mir wer behilflich sein??
€dit: Problem gelöst, ich hatte den falschen Provider angegeben und dass obwohl ich den obigen Provider auf den MSDN Seiten vorgeschlagen wurde -.-). Der korrekte Provider lautet: Provider=Microsoft.SQLSERVER.CE.OLEDB.3.5.
Hallo, gestern bin ich auf Sandcastle und die GUI sandcastle Help File Builder gestoßen und finde es ein gutes Tool um Help-Files zu erstellen. Doch leider habe ich ein Problem und zwar will er mir manche Funktionen einfach nicht in die .chm Datei einbinden:
Konkret gehts um folgende Funktionen (es gibt bestimmt noch mehr, aber ber der Klasse ist es mir halt aufgefallen):
//siehe edit weiter unten
Hab schon alles mögliche versucht damit diese Funktionen auch aufgelistet werden, aber es klapt einfach nicht. Hat vielleicht von euch jemand ne Idee woran dass liegt?
€dit: also das Problem konnte ich eingrenzen auf die unten angegebene Methode. Sobald ich diese auskommentiere wird die Hilfe zu dieser Klasse, mit allen ihren funktionen und members korrekt angezeigt:
protected virtual Dictionary<string, object> GetPropertyValues()
{
var dict = (from pi in this.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)
where pi.CanRead == true && pi.CanWrite == true
select pi).ToDictionary(x => x.Name, x => x.GetValue(this, null));
return dict;
}
€dit 2: hab den Bug jetzt weiter eingegrenzt:
var dict = this.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)
// .Where(x => (x.CanRead && x.CanWrite))
// .ToDictionary(x => x.Name, x => x.GetValue(this, null));
wenn ich die Zeile mit Where() auskommentiere, tritt der oben genannte Bug auf. Jetzt verwende ich halt erstmal folgendes Workaround:
Dictionary<string, object> dict = new Dictionary<string, object>();
var propertyInfos = this.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
foreach (var item in propertyInfos)
{
if (item.CanRead && item.CanWrite)
dict.Add(item.Name, item.GetValue(this, null)); ;
}
Ich poste dass nur damit falls jemand das gleiche Problem wie ich haben sollte sich nicht den ganzen Tag auf Fehlersuche begibt 😉
Habe das Forum durchsucht und m.E. sogar fast die gleiche Frage einmal gefunden, die Antwort bringt mich aber so garnicht weiter irgendwie..
bist bestimmt auf "meinen" Thread gestoßen, denn ich hatte dem letzt die selbe frage
. Also ich habe das Problem so gelöst, das ich meine ganzen Daten in eine lokale SQL Datenbank gepackt habe und danach dass Ganze mittels Linq2Sql gemapped habe (das sind dann meine Models).
Wenn ich jetzt die Daten einer Tabelle aus der Db anzeigen möchte, erstelle ich ebenfalls wie du eine ObservableCollection (was ich aber glaube ich gar net mal brauche, ich könnte auch eine normale List verwenden?):
public ObservableCollection<NetworkDrive> NetworkDrives
{
get
{
if (_networkDrives == null)
{
_networkDrives = new ObservableCollection<NetworkDrive>();
var query = _db.NetworkDrives;
foreach (var item in query) _networkDrives.Add(item);
}
return _networkDrives;
}
}
Der unterschied ist, dass ich eine if() abfrage in meinem getter habe und diese Daten erstmal zwischenspeichere, dadurch wird "nicht einfach eine neue ObservableCollection erzeugt". Aber ganz gelöst habe ich glaub das Problem noch nicht, denn wenn ich im Code eine neue Zeile hinzufügen wird diese nicht automatisch hinzugefügt. Hab das aber nicht getestet da dass bei mir sowieso nicht vorkommt. Aber dafür werde ich bestimmt auch noch eine Lösung finden, da ich aber gerade in "Prüfungsstreß" bin, habe ich keine zeit um weiter an das Projekt weiter zu arbeiten.
Aber dadurch, dass ich die Tabellen mit Linq2SQL gemapped habe, ist die Datenbank an die Collection gebunden und wenn ich in einer DataGrid einen Wert ändere, wird er auch in der Datenbank gespeichert (natürlich erst, wenn .SubmitChanges() aufgerufen wird). Gleiches gilt fürs löschen oder hinzufügen einer neuen Zeile.
Wie man es aber ohne Datenbank und Linq2SQL macht, weiss ich gerade auch nicht. Ich **denke **man muss da dann wirklich für jede Operation (Add, Remove, ...) in der ModelSchicht eine Funktion anbieten, und die ModelSchicht muss Änderungen immer mittels INotifyChanged bekanntgeben (sollte klar sein).
Ich hoffe ich konnte dir ein wenig auf die Sprünge helfen, wenn nicht einfach warten bis sich ein kompetenterer user meldet 😃
Halo Gemeinde,
gestern bin ich auf dieses Projekt (auch bei codeplex vorhanden) aufmerksam geworden. Da ich es aber gerade nicht verwenden bzw. testen kann wollte ich mal fragen ob ihr damit schon Erfahrungen gemacht habt.
Prinzipiell würde ich sagen, dass die Idee hinter dem Projekt sehr gut ist - oder gibts vielleicht irgendwelche Nachteile?
da wäre es dann vielleicht dass sinnvollste, im Konstruktor die Checksumme zu errechnen und in eine Variable abzuspeichern. Im Destruktor dann nochmal die Checksumme errechnen und dann je nachdem das Objekt zu speichern.
Das Problem was ich aber da gerade sehe ist, dass wenn ich die Checksumme im Konstruktor errechne und speichere, die Checksumme des Objekt dadurch ja wiederrum geändert wird?
Du könntest zum Beispiel in deinem Objekt bei jeder Property Änderungen mittels INotifyPropertyChanged bekannt machen.
z.B.
public class TestClass : INotifyPropertyChanged
private string _name;
public string Name
{
get { return _name; }
set
{
if (!value.Equals(_name))
{
_name = value;
NotifyPropertyChanged("Name");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String propertyName)
{
NotifyPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
public void NotifyPropertyChanged(PropertyChangedEventArgs args)
{
//Hier eine Variable setzen, welche aussagt dass das Objekt geändert wurde.
// ...
if (PropertyChanged != null)
{
PropertyChanged(this, args);
}
}
}
Ich denke IEditableObject für die Klasse implementieren und beim EndEdit() speichern könnte das gewünschte sein.
Sollt ich mir mal
- du schreibst dir für das objekt eine "checksum" methode. diese summe merkst du dir intern im objekt. wenn es dann um das speichern geht, führst du die methode wieder aus und vergleichst sie mit der gemerkten. so weißt du das sich was geändert hat.
Die Idee gefällt mir auch ganz gut
MfG TripleX
Also ich würde dir auch empfehlen, Dateien die gerade geöffnet sind, nicht zu kopieren. Speicher die Dateien, welche gerade geöffnet sind in einer Liste und gib dem User bescheid dass die und die Dateien nicht gesichert werden konnten. Dann kannst du ihm noch die Möglichkeit geben, zu einem späteren Zeitpunkt diese Dateien zu sichern - oder ihm die möglichkeit geben, die geöffneten Dateien trotzdem zu sichern.
btw @ViperNeo: Wenn du Probleme mit irgendwas hast, immer deinen Quellcode mitschicken, damit wir sehen können was du bisher versucht hast.
mfG TripleX
ich verwende zwar kein Prism , aber meine ViewModelBase besteht (bisher) aus:
public abstract class ViewModelBase : DispatcherObject, INotifyPropertyChanged, INotifyPropertyChanging, IDisposable
und meine ValidatingViewModelBase besteht aus:
public class ValidatingViewModelBase : ViewModelBase, IDataErrorInfo
deine 2te frage kann ich dir nicht beantowrten, da ich wie gesagt nicht mit Prism arbeite.
MfG TripleX
einfach die Fehlermeldung ignorieren, oder die Beta von Visual Studio 2010 runterladen. Wenn du viel mit WPF arbeitest, würde ich dir das sogar empfehlen. Die Beta macht zwar manchmal nochn paar zicken, aber man kann gut damit arbeiten.
verwendetes Datenbanksystem: SQL Compact 3.5 mit LinQ
Halo Gemeinde,
ich habe folgendes Problem: Ich habe eine SQL Compact 3.5 Datenbank welche mittels Linq2Sql (automatisch) gemapped wurde.
Jetzt wollte ich einer DataGrid Daten aus einer Tabelle anzeigen lassen, damit der Benutzer diese ändern kann. Dazu habe ich mir eben ein DataGrid erstellt und die Items an eine Observable-Collection gebunden. Das Ganze funktioniert soweit und cih kann Daten ändern und diese werden auch in der Datenbank gespeichert.
Jetzt wollte die Funktion einbinden, dass wenn der User auf den Button "Cancel" drückt, die Änderungen nicht in die Datenbank übernommen werden. Nur wenn der User auf "Save" klickt sollen die Daten commitet werden. Aber irgendwie steh ich da aufm Schlauch. Also folgendes habe ich bisher:
View mit DataGrid:
<DataGrid ItemsSource="{Binding NetworkDrives}"
AutoGenerateColumns="False"
>
<DataGrid.Columns>
<DataGridTextColumn Header="Server-Address" Binding="{Binding UNC}"/>
<DataGridTextColumn Header="Standard Drive Letter" Binding="{Binding StandardDriveLetter}"/>
<DataGridCheckBoxColumn Header="Mount On Connect" Binding="{Binding MountOnConnect}" />
</DataGrid.Columns>
</DataGrid>
ViewModel mit der Observable Collection und den Commands zum speichern bzw. abbrechen:
#region Private Members
private ObservableCollection<NetworkDrive> _networkDrives;
private DbTransaction _transaction;
private Database _db;
#endregion
#region Public Properties
public ObservableCollection<NetworkDrive> NetworkDrives
{
get
{
if (_networkDrives == null)
{
_networkDrives = new ObservableCollection<NetworkDrive>();
var query = _db.NetworkDrives;
foreach (var item in query) _networkDrives.Add(item);
}
return _networkDrives;
}
}
#endregion
//...
private void ExecuteSaveDataCommand()
{
_transaction.Commit();
}
//...
private void ExecuteCancelCommand()
{
_transaction.Rollback();
}
//...
public NetworkDrivesSettingsViewModel()
{
_db = new Database(@"Data Source=.\database.sdf");
_db.Connection.Open();
_transaction = _db.Connection.BeginTransaction();
_db.Transaction = _transaction;
}
#endregion
Nur funktioniert das ganze nicht wie gewünscht, denn er speichert mir gar keine Änderungen ab. Was mache ich falsch?
Btw, noch ne andere Frage - wollte deswegen keinen neuen Thread aufmachen:
Ist es in Ordnung wenn ich DataBase als Singleton implementiere (Das Programm ist nicht multiuser-fähig)?
in Visual Stusio 2010 ist IntelliSense auch deutlich schlauer geworden. gibt man zum Beispiel TextBox ein, findet er auch alle textBoxen, welche zum Beispiel "NameTextBox" heissen 👍
Hallo Gemeinde,
ich wollte mal wissen, wie man (im MVVM-pattern) am besten einen DialogResult setzt. Um das DialogResult direkt gehts mir weniger, sondern darum dass ein dialog geschlossen wird. Beim "Cancel" Button gibts da ja keine Probleme, da sich das Fenster automatisch schließt, aber beim IsDefault Button möchte ich es eben gerne so haben, dass das Fenster geschlossen wird. Bisher habe ich das mit nem Click-Event im Code-Behind geregelt (wo ich dann DialogResult=true gesetzt habe), ist zwar nicht ganz im Sinne von MVVM, aber da dass ja eine GUI-Geschichte ist bin ich recht zufrieden.
Ich wollte aber mal fragen ob es auch ohne Code-Behind Datei geht.
welche Version von Visual Studio verwendest du denn? Denn soweit ich mich erinnern kann hatte ich das Problem beim 08er ebenfalls. Das war mit ein Grund warum ich auf die 10 umgestiegen bin.
du könntest versuchen, mittels dem OutputDataReceived-Event oder dem StandardOuput-Stream die Ausgabe in der Console anzeigen zu lassen.
btw, was sollte:
Console.WriteLine(putty.Start());
bezwecken?
Hallo Gemeinde,
ich habe seit kurzem die Reflection.Emit entdeckt und bin begeistert was man nicht alles in .NET machen kann. Jetzt hätte ich eine Idee, aber bevor ich lange rumprobiere wollte ich euch mal fragen ob es Prinzipiell möglich ist.
Mich nervt es dass ich, wenn eine Property mit INotifyPropertyChanged-Funktion, haben möchte mir extra eine private Variable erstellen muss (kennt sicher jeder). Jetzt Hatte ich die Idee das vielleicht mittels Reflection.Emit die set-Funktion der property überschreiben / ändern könnte, damit eben die Funktion von INotify aufgerufen wird. Dazu würde ich mir eine Klasse schreiben (z.B. PropertyObserver *g) und dort alle Properties einer angegeben Klasse auslese und umändere.
So - wäre so etwas möglich oder kann man generell keine Funktionen "ändern". Ich glaube eher zweiteres, denn es könnte eine potenzielle Gefahr geben wenn man Funktionen abändert. Aber vielleicht geht es ja doch??
MfG TripleX
danke für eure Antworten.
@TripleX
*.dbml ist eine Linq-To-SQL Meta-Datei. Das hat nix mit einem DataSet zu tun. L2S ist ein einfacher O/R-Mapper, der in den meisten Fällen eh einfacher zu verwenden ist als ein DataSet. Das ist nicht deine Datenbank sondern eine Datei welche die Datenbank beschreibt. Die Datenbank ist eine andere Datei die bei SQL Compact normalerweise direkt daneben liegt und auf *.sdf endet.
Danke nochmal für den Hinweis, aber dass wusste ich schon, da ich gerade durch das Thema O/R Mapper auf das ganze Thema hier gekommen bin.
Meine Frage wegen dem DataSet war eher so gedacht: Ich habe in einem Projekt meine "Datenbank" (in dem Fall dann das DataSet welche die Daten einer xml-Datei eingelesen bekommt.) In einem anderen Projekt habe cih dann meine "Models", was in dem Falle die *.dbml Datei wäre. Jetzt wollte ich halt wissen ob man die *.dml irgendwie mit dem DataSet verknüpfen kann. Beim der SQL Compact Datenbank muss ich dafür die Tabellen im *.dbml erstellen und einen ConnectionString angeben. Ersteres würde ich hinkriegen bei einem DataSet, aber dann bin ich am verbinden des DataSets mit dem O/R-Mapper gescheitert.
Denn cih habe gerade ein kleiens Projekt, wo eine SQL-Datenbank eigentlich viel zu "overweight" ist. Außerdem möchte ich den benutzern nicht zumuten, sich extra SQL Compact 3.5 herunterzuladen (oder ich liefere die *.dlls mit, worauf cih auch gerne verzichte würde). Deswegen würde ich Daten am liebsten in eine xml-Datei in Verbindung mit einem DataSet speichern.
MfG TripleX
ich weiß selber nicht mehr, was ich mir bei max gedacht habe. Ich glaube dass ich damit den endwert für die schleife meinte. dadurch merkt man wie wichtig eine saubere Benennung der Variablen ist. Ich habe bei dem beispiel leider auf eine saubere benennung der variablen (+ Funktionen) verzichtet, da ich nur schnell eine Lösung präsentieren wollte. Wird in Zukunft (hoffentlich) nicht mehr passieren.
MfG TripleX
Hallo Gemeinde,
ich habe mir heute überlegt ob es nicht sinnvoll wäre, bei der Implementierung von INotifyPropertyChanged einen "Cache" einzubauen.
Der Vorteil den ich sehe ist der, dass nicht immer ein neues PropertyChangedEventArg erstellt werden muss sobald die Funktion aufgerufen wird.
Nachteil ist dabei aber dass die Klasse etwas "größer" wird (vom Speicherverbrauch) und dass er jetzt bei jeder ChangeNotification erstmal das Dictionary durchsuchen muss:
private readonly Dictionary<string, PropertyChangedEventArgs> _propertyChangedEventArgsCache = new Dictionary<string, PropertyChangedEventArgs>();
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventArgs args;
if (!_propertyChangedEventArgsCache.TryGetValue(propertyName, out args))
{
args = new PropertyChangedEventArgs(propertyName);
_propertyChangedEventArgsCache.Add(propertyName, args);
}
NotifyPropertyChanged(args);
}
public void NotifyPropertyChanged(PropertyChangedEventArgs args)
{
if (PropertyChanged != null)
{
PropertyChanged(this, args);
}
}
Was meint ihr was besser ist - ohne cache oder mit?
€dit: naja nach nem simplen Test hab ich gemerkt dass es ohne Cache viel schneller ist. War wohl ne dumme Idee 😃
MfG TripleX
Was mir noch auffält: Wenn du das Minimum berechnet, solltest du es auch Minimum nennen und nicht Maximum 😄
Kein kommentar 👅
Math.Min(a.Count, b.Count)
danke hab dass auch direkt mal getestet welches (nach 100010001000 Aufrufe) von den beiden schneller. Es tritt an:
int min = 123 < 60 ? 123 : 60;
//vs.
int min = Math.Min(123, 60);
:question: : 3941
Math.Min: 5338
Auf die 1,4 Sekunden kommt's dann auch nicht wirklich an, und die Math.Min()-variante ist eindeutig besser zu verstehen
das mit der CompareTo ist eine super idee 😃[/csharp]
aber deinen Einwand mit a_ != b_ kann ich nicht verstehen. Habe es mal getestet und CompareByNumber("1.1","1.0") liefert mir eine 1 zurück (was auch richtig ist)
hab es mal mit linq getestet und es funktioniert ebenso:
private static int CompareByNumber(String x, String y)
{
if (x == y) return 0;
var a = x.Split('.').Select((z) => Convert.ToInt32(z));
var b = y.Split('.').Select((z) => Convert.ToInt32(z));
int max = a.Count() < b.Count() ? a.Count() : b.Count();
for (int i = 0; i < max; i++)
{
if (a.ElementAt(i).CompareTo(b.ElementAt(i)) != 0)
return a.ElementAt(i).CompareTo(b.ElementAt(i));
}
return a.Count() - b.Count();
}
Btw, wollte mal schauen welche Methode schneller ist:
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 1000; i++)
{
for (int j = 0; j < 1000; j++)
{
List<string> strings = new List<string>() {
{ "1.1" }, { "1.0"}, {"1.123456"},
{ "1.1.2" }, { "1.7" }, { "1.2.1.2"},
};
strings.Sort(CompareByLinq);
}
}
watch.Stop();
Console.WriteLine("CompareByLinq: " + watch.ElapsedMilliseconds);
watch.Reset();
watch.Start();
for (int i = 0; i < 1000; i++)
{
for (int j = 0; j < 1000; j++)
{
List<string> strings = new List<string>() {
{ "1.1" }, { "1.0"}, {"1.123456"},
{ "1.1.2" }, { "1.7" }, { "1.2.1.2"},
};
strings.Sort(CompareByNumber);
}
}
Console.WriteLine("CompareByNumber: " + watch.ElapsedMilliseconds);
watch.Reset();
Hier die Ausgabe der Konsole (Zeiten in ms)
CompareByLinq: 104122
CompareByNumber: 15268
wow danke, ich hätte schon viel eher fragen sollen. Wirklich genial das Programm. (ein paar Sachen werde ich zwar noch ändern aber an sich bin ich sehr zufrieden)
Also ich habe jetzt mal die "local database" (SQL Compact 3.5) genommen und bin damit Recht zufriden. Was ich genial daran finde ist, dass man sich mittels dem Programm sqlmetal eine *.dbml - Datei generieren kann. Ist wirklich eine sehr schöne Sache. 👍
Weiß zufällig jemand ob man diese *.dbml auch mit einem dataset (welches die Daten aus einer xml-Datei bekommt) verwenden kann. Habe mich gestern daran versucht aber habs nicht hingekriegt 🤔
Ich habe noch nie "Add Item" geklickt, ich schreibe immer den Code direkt ohne Assistent. Siehe Link in meiner Signatur.
hast du da wirklich noch nie darauf geklickt 8o?
PS: Mit LINQ kann man da noch einiges kürzer zaubern, aber implementiers doch erstmal so
Könntest du mal zeigen wie, oder zumindest die Vorgehensweise erläutern?
Hallo Gemeinde,
da ich Ordnung liebe (zumindest in Quellcode *g) wollte ich mal fragen ob es eine möglichkeit gibt (z.B. über Addins oder ähnliches) meinen Code folgendermaßen zu sortieren:
public class NetworkDriveViewModel : ViewModelBase
{
#region Private Members
//...
#endregion
#region Public Properties
//...
#endregion
#region Public Commands
//...
#endregion
#region Public Actions
//...
#endregion
#region Public Events
//...
#endregion
#region Constructors
//...
#endregion
#region Private Methods
//...
#endregion
#region EventHandling
//...
#endregion
#region IDisposable Implemetation
//...
#endregion
}
Am besten wäre es halt dass ich nur ein Button drücke, dann wird eine Funktion aufgerufen der meinen Code analysiert und die #regions (je nach Bedarf) einfügt
Denn ich verbrauche viel zeit dafür, in meinen ganzen Klassen den Code so "sauber" zu halten. Da kann es eig. nicht schaden etwas Zeit zu investieren in eine Funktion, die dass automatisch macht. Ich könnte natürlich auch ein eigenes Programm dazu schreiben, aber ich bräuchte halt aufjedenfall einen Shortcut oder Button im Visual Studio.
MfG TripleX
hallo Gemeinde, ich habe mir demletzt einige Codesnippets gebastelt, und wollte diese euch natürlich nicht vorenthalten (habe im Forum nach einem Sammelthread oder ähnliches gesucht, bin aber nicht fündig geworden).
Singelton-Pattern (singleton)
Implementiert (fast) das Singleton-pattern. Der private Konstruktor muss noch erstellt werden.
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet" >
<CodeSnippet Format="1.0.0">
<Header>
<Title>Singleton Snippet</Title>
<Shortcut>singleton</Shortcut>
<Description>Code snippet for implementing the Singleton Pattern (Threadsafe)</Description>
<Author>David Teck</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal Editable="false">
<ID>TypeObject</ID>
<Function>SimpleTypeName(System.Object)</Function>
</Literal>
<Literal>
<ID>classname</ID>
<ToolTip>Class name</ToolTip>
<Function>ClassName()</Function>
<Default>ClassNamePlaceHolder</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[$end$#region Singleton
private static volatile $classname$ _instance;
private static object _lock = new $TypeObject$();
/// <summary>
/// Get the unique instance of <see cref="$classname$"/>.
/// This property is thread-safe.
/// </summary>
public static $classname$ Instance
{
get
{
if (_instance == null)
{
lock (_lock)
{
if (_instance == null) _instance = new $classname$();
}
}
return _instance;
}
}
#endregion]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
NotifyProperty (notprop)
Erstellt eine Property, welche Änderungen - über meine Implementierung von INotifyPropertyChanged (siehe weiter unten) - bekannt gibt.
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet" >
<CodeSnippet Format="1.0.0">
<Header>
<Title>NotifyProperty Snippet</Title>
<Shortcut>notprop</Shortcut>
<Description>Code snippet for a Property which notifies updates with INotifyPropertyChanged</Description>
<Author>David Teck</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>The type of the property</ToolTip>
<Default>bool</Default>
</Literal>
<Literal>
<ID>fieldname</ID>
<ToolTip>The name of the property</ToolTip>
<Default>name</Default>
</Literal>
<Literal>
<ID>propname</ID>
<ToolTip>The name of the property</ToolTip>
<Default>Name</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[private $type$ $fieldname$;
public $type$ $propname$
{
get { return $fieldname$; }
set
{
if (value != $fieldname$)
{
$fieldname$ = value;
NotifyPropertyChanged("$propname$");
}
}
}$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
INotifyPropertyChang(ed/ing) Implementierung (inotitfy):
Implementiert das INotifyPropertyChanged-Interface oder das INotifyPropertyChanging-Interface
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet" >
<CodeSnippet Format="1.0.0">
<Header>
<Title>INotifyPropertyChang(ed/ing) Snippet</Title>
<Shortcut>inotify</Shortcut>
<Description>Code snippet for implementing INotifyPropertyChang(ed/ing)</Description>
<Author>David Teck</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>event</ID>
<ToolTip>This specifies the type of the event</ToolTip>
<Default>ed</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[$end$#region INotifyPropertyChang$event$ Implementation
/// <summary>
/// Declares the <see cref="PropertyChang$event$"> event
/// </summary>
public event PropertyChang$event$EventHandler PropertyChang$event$;
/// <summary>
/// This method will raise the <see cref="PropertyChang$event$"> event passing the
/// source property that is being updated.
/// </summary>
/// <param name="propertyName">Name of the chang$event$ property.</param>
public void NotifyPropertyChang$event$(String propertyName)
{
NotifyPropertyChang$event$(new PropertyChang$event$EventArgs(propertyName));
}
/// <summary>
/// This method will raise the <see cref="PropertyChang$event$"> event passing the
/// source properties that are being updated.
/// </summary>
/// <param name="propertyNames">Name of the chang$event$ properties.</param>
public void NotifyPropertyChang$event$(String[] propertyNames)
{
foreach(string prop in propertyNames)
NotifyPropertyChang$event$(new PropertyChang$event$EventArgs(prop));
}
/// <summary>
/// This method will raise the <see cref="PropertyChang$event$"> event passing the
/// source property that is being updated.
/// </summary>
/// <param name="args"><see cref="PropertyChang$event$EventArgs"/> of the chang$event$ property.</param>
public void NotifyPropertyChang$event$(PropertyChang$event$EventArgs args)
{
if (PropertyChang$event$ != null)
{
PropertyChang$event$(this, args);
}
}
#endregion]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
IDisposable Implementierung (idisposable):
Implementiert das IDisposable-Interface
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet" >
<CodeSnippet Format="1.0.0">
<Header>
<Title>IDisposeable Snippet</Title>
<Shortcut>idisposable</Shortcut>
<Description>Code snippet for implementing IDisposeable</Description>
<Author>David Teck</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>classname</ID>
<ToolTip>Class name</ToolTip>
<Function>ClassName()</Function>
<Default>ClassNamePlaceHolder</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[$end$#region IDisposable Implemetation
~$classname$ ()
{
Dispose (false);
}
/// <summary>
/// Disposes the <see cref="$classname$"/>
/// </summary>
public void Close ()
{
((IDisposable)this).Dispose ();
}
/// <summary>
/// Closes and disposes the <see cref="$classname$"/>
/// </summary>
void IDisposable.Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
/// <summary>
/// This method is called by <see cref="Dispose()"/>.
/// Derived classes can override this method.
/// </summary>
/// <param name="cleanManagedResources">
/// <para><see langword="true"/>: Disposes managed and unmanaged resources</para>
/// <para><see langword="false"/>: Disposes only unmanaged resources</para>
/// </param>
protected virtual void Dispose(bool cleanManagedResources)
{
if (cleanManagedResources)
{
// Clean up the managed resources
}
// Clean up the unmanaged resources
}
#endregion]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
Event (event)
Erstellt ein simples event
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet" >
<CodeSnippet Format="1.0.0">
<Header>
<Title>Event Snippet</Title>
<Shortcut>event</Shortcut>
<Description>Code snippet for creating an event</Description>
<Author>David Teck</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>name</ID>
<ToolTip>Specify the name of the event</ToolTip>
<Default>MyEvent</Default>
</Literal>
<Literal>
<ID>comment</ID>
<ToolTip>Specify the XML-Comment for the event</ToolTip>
<Default></Default>
</Literal>
<Literal>
<ID>access</ID>
<ToolTip>Specify the accessibility the event</ToolTip>
<Default>public</Default>
</Literal>
<Literal>
<ID>handler</ID>
<ToolTip>Specify the EventHandler for the event</ToolTip>
<Default>EventHandler</Default>
</Literal>
<Literal>
<ID>param</ID>
<ToolTip>Specifies the parameter for the event</ToolTip>
<Default>EventArgs.Empty</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[$end$#region $name$-Event
/// <summary>
/// Occurs when $comment$
/// </summary>
$access$ event $handler$ $name$;
private void On$name$()
{
if ($name$ != null) $name$(this, $param$);
}
#endregion]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
SimpleCommand (mvvm_simcom)
_Erstellt einen neuen SimpleCommand (Command für WPF) _
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet" >
<CodeSnippet Format="1.0.0">
<Header>
<Title>MVVMFrameWork - SimpleCommand Snippet</Title>
<Shortcut>mvvm_simcom</Shortcut>
<Description>Code snippet for a SimpleCommands</Description>
<Author>David Teck</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Imports>
<Import>
<Namespace>MVVMFrameWork.Commands</Namespace>
</Import>
</Imports>
<Declarations>
<Literal>
<ID>fieldname</ID>
<ToolTip>The name of the command</ToolTip>
<Default>name</Default>
</Literal>
<Literal>
<ID>propname</ID>
<ToolTip>The name of the command</ToolTip>
<Default>Name</Default>
</Literal>
<Literal>
<ID>cancode</ID>
<ToolTip>The code which indicates if the command can be executed</ToolTip>
<Default>true</Default>
</Literal>
<Literal>
<ID>docode</ID>
<ToolTip>The code which will be executed</ToolTip>
<Default></Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[$end$#region $propname$Command
private SimpleCommand $fieldname$Command;
public SimpleCommand $propname$Command
{
get {
if ($fieldname$Command == null)
$fieldname$Command = new SimpleCommand(x => Execute$propname$Command(), x => CanExecute$propname$Command);
return $fieldname$Command;
}
}
/// <summary>
/// Called, when the <see cref="$propname$Command"/> should be executed.
/// </summary>
private void Execute$propname$Command()
{
$docode$
}
/// <summary>
/// <see langword="true"/> if the <see cref="$propname$Command"/> can be executed.
/// </summary>
private bool CanExecute$propname$Command
{
get
{
return $cancode$;
}
}
#endregion]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
Falls ihr Verbesserungsvorschläge oder andere Snippets habt, welche ihr austauschen möchtet, dann postet sie doch bitte hier 😃
Schlagwörter: Singleton, INotifyPropertyChanged, IDisposable, SimpleCommnd, Snippet
private static int CompareByNumber(String x, String y)
{
if (x == y) return 0;
string[] a = x.Split('.');
string[] b = y.Split('.');
int max = a.Length < b.Length ? a.Length : b.Length;
for (int i = 0; i < max; i++)
{
if( a[i] != b[i] ) return (Convert.ToInt64(a[i]) - Convert.ToInt64(b[i])) > 0 ? 1 : -1;
}
return a.Length - b.Length;
}
List<string> strings = new List<string>() {
{ "1.1" }, { "2.2.3.4"}, {"1.123456"},
{ "1.1.2" }, { "1.7" }, { "1.2.1.2"},
};
strings.Sort(CompareByNumber);
Keine Garantie auf Richtigkeit, aber die liste sieht nach'm sortieren gut aus. Anstatt Convert.ToInt64() kann man natürlich auch Convert.ToInt32 (oder die TryParse Methode, welche oben bereits angesprochen wurde), verwenden.
ja natürlich macht das Sinn, nur ich habe daran nicht gedacht - und ich war halt froh dass ich es (nach ner langen nacht) hingekriegt habe. Jetzt werden es wohl ein paar Nächte mehr werden dass ich dran arbeite.
sieht sehr gut aus (für ein Schulprojekt!)
Screeenshot: siehe anhang
danke für deinen Beitrag, hat mir weitergeholfen! Werde nachher mal schauen wie das ist, wenn ich 2 Events abfangen möchte, hab das nämlich noch gar nicht probiert hehe
€dit: ja das geht nicht ... 'Property is set more than once' ... und ich hab mich schon gefreut dass es funktioniert 👅
@Mr. Evil:
so schlau ist meine Implementierung noch nicht, ich kann bisher nur folgendes machen:
MVVM:EventBinding.Event="Loaded"
MVVM:EventBinding.Action="{Binding LoadedAction}"
MVVM:EventBinding.Command="{Binding LoadedCommand}"
MVVM:EventBinding.CommandParameter="{Binding CommandParameter}"
Aber so reicht mir das erstmal. Sobald ich mehr brauche, wird es eben implementiert 😃
die loesung mit dem link zuvor ist problematissch wenn man mehrere events binden moechte aber die controls keine child elemente im visual tree erlauben - dann geht das nicht
kannst du dazu mal ein kurzes beispiel posten? verstehe nämlich nicht ganz was du meinst.
Dafür musst du dir (leider) selber eine Klasse zusammenbasteln oder eine bereits fertige Implementierung verwenden (Stichpunkt EventBinding oder AttachedCommands).
Dass ganze ist aber, wenn du es selber baust nicht ganz einfach., da man mit Reflection arbeiten muss. Die Klassen vom oben angegeben Link habe ich bs vor wenigen Minuten selber noch verwendet, bin aber gerade fertig mit meiner eigener Implementierung geworden.
Wenn du Fragen hast, einfach fragen 😃
MfG TripleX
Problem behoben ... ich hatte (weil ich es früher gebraucht habe) als Datentyp von StatusImage ImageSource, habe es jetzt in string geändert und jetzt geht's 😃
verwendetes Datenbanksystem: weiss i no net 👅
Hallo Gemeinde,
ich habe mal eine Frage wie man (lokale) Daten in einer Datebank am besten speichert.
Bisher habe ich immer ein dataset verwendet, welches ich als xml-datei gespeichert habe. Aber da gibts doch bestimmt bessere Alternativen. Also wenn ich in meinem Projekt auf "Add / New Item" klicke, bekomme ich ja ein paar Sachen angezeigt (siehe Daeianhang).
Was mir ins Auge springt ist die "local database". Doch wenn ich das Projekt weitergebe an jemand anders, der nur .NET Framework installiert hat (und kein SQL-Server oder ähnliches), funktioniert dass dann trotzdem? Gibts sonst noch alternativen?
Außerdem werde ich, wenn ich des auswähle, nach einem Typ gefragt (zur Auswahl stehen DataSet und Entinity Data Model) 🤔
MfG TripleX
Also wenn der Pfad zur Datei sicher stimmt (am besten davor immer mit Files.Exist() prüfen) dann könnte es meiner Meinung nach nur noch am leerzeichen liegen 🤔. Probier mal die Datei umzubenennen in "Intel_Chipset.exe"
Ich habe in Erinnerung das "Environment.CurrentDirectory" keine gute Wahl ist. Verwende lieber "AppDomain.CurrentDomain.BaseDirectory"
Lies dir am besten mal den Thread durch (auch den hinweis ganz unten!)
[FAQ] Pfad zur eigenen Anwendung (EXE) ermitteln
Das geht mittels .:
Dieser Operator trifft auf jedes einzelne druckbare oder nicht druckbare Zeichen zu, außer unter Umständen auf ein Newline-Zeichen (Neue Zeile) oder auf Null-Zeichen, also leere Strings. Das Punktzeichen (.) repräsentiert diesen Operator