Da steht nur System.Windows.Forms, weil es ein Forms-Projekt ist, ansonsten hat der Fehler damit nichts zu tun.
Eine spontane Idee (ungetestet) waär im Xaml bei MenuItem die Tag Eigenschaft einfach frech zu nutzen.
Das ist ja noch frickeliger als die ParentParent-Variante. 😄
pictureBox1.Image.Dispose();
Das wars, ich habe die Zeile "Dispose()" entfernt. Jetzt wird das Bild korrekt angezeigt.
Nur wird diese Methode noch gar nicht aufgerufen. (Ja, habe das mit Haltepunkt getestet!)
Ähm, hä? 🤔
Wenn du diese Zeile wieder einfügst, geht es dann wieder nicht?
Also ich kann mir das nicht vorstellen, dass es daran lag...
Warum musst du den Code pro Image hinschreiben? 🤔
Der Code funktioniert bei mir einwandfrei.
Hast du an der PictureBox evtl. irgendeine Einstellung geändert?
Ich habe einfach nur eine PictureBox und einen Button auf ein Fenster gezogen und lade beim Klick auf den Button ein Bild aus den Beispielbildern.
Den ersten Teil meiner Antwort zu deinem Problem hast du ja sicher auch gelesen. =)
Und - sei mir nicht böse - wenn so eine Frage gestellt wird, dann darf man das gerne mal hinterfragen.
oder du machst einen Verweis auf die Datei via Pfad (2 roter Rahmen).
Ähm nein, bitte niemals so lösen.
Das fliegt dir um die Ohren, wenn sich die Pfade ändern bzw. ein Buildtool das Projekt bauen soll.
Den Namen brauchst du doch gar nicht.
Was du brauchst, ist das Image (siehe deine Methode!).
Wenn du auf ein MenuItem klickst, dann ist der Sender das MenuItem. Der Parent ist das ContextMenu. Und der Parent vom ContextMenu wiederum müsste das Image sein...
Wobei es schon sehr frickelig aussieht, was du da machst.
EDIT sagt noch:
...weil string und Image nicht zusammenpassen. Kann man das konventieren?
Die Frage deutet darauf hin, dass dir einige Grundlagen fehlen.
[FAQ] Wie finde ich den Einstieg in C#?
Windows.Forms ist in dem Fall trotzdem das falsche Unterforum. 😉
Evtl. kann man den Store vom Code aus "aktualisieren"? 😁
Als Idee:
Hast du die Möglichkeit, irgendwo eine Version abzufragen?
Dann hättest du die Möglichkeit zu sagen "Ähm, du nutzt Version 1, es gibt aber schon Version 2, update mal". Weiß aber nicht, ob das ein guter Weg ist. 😁
Also ich habe es erst mit einem Button ausprobiert, da hat es wunderbar funktioniert. =)
Ist der DataContext richtig gesetzt?
Hast du mal in den Output geschaut, ob du Bindingfehler hast?
Ohne es getestet zu haben: du bist im falschen Bereich.
Probiere statt <MenuItem.ItemContainerStyle> mal <MenuItem.Style> aus.
EDIT: Das Command im MenuItem ist bestimmt nur experimentell drin? 😄
Hmm, sieht jetzt erstmal nicht verkehrt aus.
Mit Telerik kann ich es nicht testen.
Mit einem normalen DataGrid tritt der Fehler bei mir auf jeden Fall nicht auf. 🤔
Und das XAML?
Okay, kannst du dann den Code mal in abgespeckter Version zur Verfügung stellen?
Versuche mal bitte nachzustellen, ob das Problem auch dann auftritt, wenn du nicht das RadGridView von Telerik verwendest.
Das heißt, dass dabei die Methode OnCreate wieder ausgeführt wird.
Nicht unbedingt. 😉
Allerdings ist es einfacher den start mit
startActivityForResult
...onActivtyresult
Nice! 🙂
Schaue dir mal den Activity Lifecycle an. =)
@witte:
Ja, der Typ des DataContext wurde gesetzt, sonst würde es ja für das DataGrid auch nicht gehen. 😉
Für alle 3 Controls werden beim Setzen der ItemsSource die Properties des VM angeboten.
Zudem ist beim DataGrid und beim MyItemsControl die Autovervollständigung für die Columns anhand der Properties des Typs der ItemsSource möglich...
<DataGrid Grid.Row="1" ItemsSource="{Binding MyList}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Z" Binding="{Binding Zahl}" /> <!-- Autovervollst. anhand der Properties des Typs der ItemsSource möglich -->
<DataGridTextColumn Header="T" Binding="{Binding Text}" /> <!-- Autovervollst. anhand der Properties des Typs der ItemsSource möglich -->
</DataGrid.Columns>
</DataGrid>
<views:MyItemsControl Grid.Row="2" ItemsSource="{Binding MyList}"> <!-- vom ItemsControl abgeleitet -->
<views:MyItemsControl.Columns>
<DataGridTextColumn Header="Z" Binding="{Binding Zahl}" /> <!-- Autovervollst. anhand der Properties des Typs der ItemsSource möglich -->
<DataGridTextColumn Header="T" Binding="{Binding Text}" /> <!-- Autovervollst. anhand der Properties des Typs der ItemsSource möglich -->
</views:MyItemsControl.Columns>
</views:MyItemsControl>
<views:MyControl Grid.Row="3" ItemsSource="{Binding MyList}"> <!-- vom Control abgeleitet -->
<views:MyControl.Columns>
<DataGridTextColumn Header="Z" Binding="{Binding Zahl}" /> <!-- Zahl wird unterkringelt und im VM gesucht -->
<DataGridTextColumn Header="T" Binding="{Binding Text}" /> <!-- Text wird unterkringelt und im VM gesucht -->
</views:MyControl.Columns>
</views:MyControl>
@ErfinderDesRades:
Dein vierter Satz ist meine Frage. 😉
Würde gerne wissen, wie man diese Abhängigkeit hinbekommt.
Natürlich wäre es am einfachsten, selbst vom ItemsControl zu erben, allerdings ist das nicht unbedingt immer möglich. Also wäre es gut, wenn man weiß, wie es funktioniert. =)
Welche XAML meinst du denn jetzt?
Moin,
bevor ich zu meiner Frage komme, zuerst ein Beispiel zum besseren Verständnis.
Gegeben ist folgende Situation:
public class MeineTolleKlasse
{
public string Text { get; set; }
public int Zahl { get; set; }
}
//Property in meinem ViewModel
IList<MeineTolleKlasse> MyList { get; }
In der dazugehörigen View kann ich nun mit Hilfe der Intellisense des ReSharpers die Bindings für die DataGridTextColumn problemlos vervollständigen, da er den korrekten Typ der ItemsSource automatisch erkannt hat (MeineTolleKlasse).
<DataGrid ItemsSource="{Binding MyList}">
<DataGrid.Columns>
<DataGridTextColumn Header="Z" Binding="{Binding Zahl}" />
<DataGridTextColumn Header="T" Binding="{Binding Text}" />
</DataGrid.Columns>
</DataGrid>
Schreibt man z.B. "{Binding Blub}", unterkringelt er Blub und gibt einen Hinweis aus - was auch korrekt ist:> Fehlermeldung:
Cannot resolve property 'Blub' in data context of type 'MeineTolleKlasse'
Die ItemsSource selbst wird in der Klasse ItemsControls definiert.
Lege ich mir jetzt ein eigenes, von ItemsControl abgeleitetes, Control an und füge in diesem Control z.B. folgende Property hinzu
public ObservableCollection<DataGridColumn> Columns { get; }
kann ich beim Definieren der Columns im XAML ebenfalls die Vervollständigung nutzen.
Nun ist mir allerdings nicht ganz klar, wie er die Verbindung zum Typ der ItemsSource herstellt.
Habe zwar bereits den Code des ItemsControl durchgeschaut, mir ist allerdings nichts aufgefallen, was helfen könnte.
Bin mir allerdings auch nicht sicher, ob es nicht "Magic" vom ReSharper ist.
Hat jemand eine Idee?
Hintergrund der Frage ist ein Control auf Arbeit, was ich gerne um diese Möglichkeit der Autovervollständigung erweitern möchte.
EDIT:
Lege ich ein Control an, was einfach nur von Control erbt, und definiere in diesem eine Dependency Property "ItemsSource" (die den gleichen Aufbau wie die DP im ItemsControl hat), kann ich die Autovervollständigung nicht nutzen.
ThomasE. ging es wohl um die Schreibweise an sich.
Das ist einfach Syntaxzucker, original würde es so aussehen:
private int GetInt()
{
return 6;
}
=)
Du kannst den letzten Teilsatz von Abt auch durch "nur weil mir deren Rechtschreibung nicht passt." ersetzen.
Ändert allerdings nicht an seiner Aussage.
Es gibt die verschiedensten Gründe für schlechte Rechtschreibung, nehmen wir z.B. mal LRS. Soll man diese User nun dafür bestrafen, dass sie dieses Problem haben?
Ich verstehe den Gedankengang von Stefan, finde es auch schade wenn sich User dem Empfinden nach keine Mühe geben einen ordentlichen Beitrag zu verfassen. Meist wird der User dann allerdings darauf hingewiesen, sollte er den Hinweis nicht beachten, kann man sich ja einfach aus der Diskussion zurückziehen.
Den Hinweis von Alf Ator bzgl. der laxeren Umgangssprache fande ich sehr gut, wenn ich über Forenbeiträge aus meiner Jugend stolpere, dann schlage ich heute die Hände über dem Kopf zusammen. 😁
Wir bauen hier keine Mauern wie andre....sowas kommt also nicht infrage.
Was hat denn das (hypotetische) blocken/bannen/löschen/deaktivieren von Usern mit Mauern bauen zu tun?
Stichwort: Ausgrenzung. 🙄
Ansonsten kann man sich der Meinung von Abt nur anschließen.
Dafür fehlen dann aber die Werte.
Ähm, nein. Ist der DataPropertyName korrekt gesetzt, werden die Werte angezeigt.
1....dann per Schleife die Werte in die DataGridViewComboBoxColumn übertragen...
Es ist nicht notwendig, Werte per Schleife woanders hin zu übertragen. Die entsprechende Column muss nur den korrekten DataPropertyName kennen...
1.Besteht dabei die Gefahr, dass bestimmte Eigenschaften vergessen werden? Immerhin wird die DataGridViewComboBoxColumn komplett manuell gefüllt ohne DataSource für die Werte, nur für die DropDownList.
...was meinst du damit? Auch eine DataGridViewComboBoxColumn muss einen DataPropertyName haben, damit die Column weiß, was sie anzeigen/"binden" soll (Werte).
Einfaches Beispiel
Gegeben sind 2 typisierte DataTables:
Entries
stellen die DataSource für die DataGridView da, die PossibleInteger
die DataSource für eine ComboBox.Diese beiden Tabellen werden nur im Konstruktor einer dummen Form befüllt.
var possibleIntegerTable = new DataSet1.PossibleIntegerDataTable();
possibleIntegerTable.AddPossibleIntegerRow(1, "One");
possibleIntegerTable.AddPossibleIntegerRow(3, "Three");
possibleIntegerTable.AddPossibleIntegerRow(5, "Five");
possibleIntegerTable.AddPossibleIntegerRow(19, "Nineteen");
var entriesTable = new DataSet1.EntriesDataTable();
entriesTable.AddEntriesRow("Eintrag 1", 19);
entriesTable.AddEntriesRow("Eintrag n", 5);
Die Entries werden einmal in einem "automatischen" DataGridView gesetzt (oberer Teil im Bild).
automaticDataGridView.DataSource = entriesTable;
Weiterhin werden in einem anderem DataGridView die Columns von Hand hinzugefügt (unterer Teil im Bild).
Spalte 2 und 3 unterscheiden sich im DisplayMember.
manualDataGridView.Columns.Add(new DataGridViewTextBoxColumn
{
HeaderText = entriesTable.Entries_NameColumn.ColumnName,
DataPropertyName = entriesTable.Entries_NameColumn.ColumnName
});
manualDataGridView.Columns.Add(new DataGridViewComboBoxColumn
{
HeaderText = entriesTable.Entries_IntegerColumn.ColumnName,
DataPropertyName = entriesTable.Entries_IntegerColumn.ColumnName,
DisplayMember = possibleIntegerTable.PossibleInteger_ValueColumn.ColumnName,
ValueMember = possibleIntegerTable.PossibleInteger_ValueColumn.ColumnName,
DataSource = possibleIntegerTable
});
manualDataGridView.Columns.Add(new DataGridViewComboBoxColumn
{
HeaderText = entriesTable.Entries_IntegerColumn.ColumnName,
DataPropertyName = entriesTable.Entries_IntegerColumn.ColumnName,
DisplayMember = possibleIntegerTable.PossibleInteger_DescColumn.ColumnName,
ValueMember = possibleIntegerTable.PossibleInteger_ValueColumn.ColumnName,
DataSource = possibleIntegerTable
});
manualDataGridView.AutoGenerateColumns = false;
manualDataGridView.DataSource = entriesTable;
Geht das auch bei DataTables?
Moin Ornithopter,
ich habe zwei gute und eine schlechte Nachricht(en) für dich:
Die erste gute Nachricht ist, dass der geschriebene Code korrekt ist - also zu den von dir geschilderten Ergebnissen passt.
Die schlechte Nachricht ist, dass du das, was du machen möchtest, einfach nicht in Codeform gebracht hast. 😉
Die zweite gute Nachricht ist, dass das, was du machen möchtest, definitiv auch technisch machtbar ist. 🙂
Vorab schon mal der Hinweis auf den [Artikel] Debugger: Wie verwende ich den von Visual Studio?.
Dadurch kann man das (korrekte) Verhalten prinzipiell nachvollziehen.
Dir macht hauptsächlich die Property DataGridView.AutoGenerateColumns
(Standardwert true) das Leben schwer.
Diese Property sorgt dafür, dass beim Setzen der DataSource (Zeitpunkt!) alle * Spalten automatisch generiert werden. Die generierten Spalten sind je nach Typ stinknormale DataGridViewTextBoxColumn
, DataGridViewCheckBoxColumn
etc.
Weiterhin nutzt du sehr wahrscheinlich falsche Bezeichner für den DataPropertyName
, wodurch einige Zellen leer bleiben.
Beispiele
Kurz 3 Beispiele zu automatisch generierten Spalten und manuell hinzugefügten Spalten und zu den Unterschieden, wann die DataSource gesetzt wird.
Gegeben ist eine DataTable MyFunnyDataTable
mit den Spalten A (string), B (bool) und C (int).
Die DataGridView myFunnyDataGridView wurde im Designer lediglich auf das Fenster gezogen (ohne Anpassungen der Standardeinstellungen).
myFunnyDataGridView.AutoGenerateColumns = true; //Standard ist true, nur zur Veranschaulichung!
myFunnyDataGridView.DataSource = new MyFunnyDataTable()
Das Ergebnis sind 3 generierte Spalten, deren DataPropertyName jeweils auf "A", "B" bzw. "C" steht.
var myFunnyDataTable = new MyFunnyDataTable();
myFunnyDataGridView.Columns.Add(new DataGridViewTextBoxColumn
{
HeaderText = "Meine schöne Spalte B",
DataPropertyName = myFunnyDataTable.BColumn.ColumnName
});
myFunnyDataGridView.AutoGenerateColumns = true; //Standard ist true, nur zur Veranschaulichung!
myFunnyDataGridView.DataSource = myFunnyDataTable
Das Ergebnis sind auch in dem Fall 3 Spalten, allerdings sieht es so aus: "Meine schöne Spalte B", "A", "C". Für Spalte B hat er keine weitere Spalte generiert.
Wenn ich das in der Reference Source von Microsoft richtig überflogen habe, merkt er sich bereits vorhandene Spalten anhand des DataPropertyName und nutzt diese dann später wieder.
Das erklärt dann, warum du manchmal einige "Originalspalten" gesehen hast (wenn der DataPropertyName nicht gestimmt hat) und manchmal nicht (wenn der DataPropertyName stimmte).
var myFunnyDataTable = new MyFunnyDataTable();
myFunnyDataGridView.AutoGenerateColumns = true; //Standard ist true, nur zur Veranschaulichung!
myFunnyDataGridView.DataSource = myFunnyDataTable
myFunnyDataGridView.Columns.Add(new DataGridViewTextBoxColumn
{
HeaderText = "Meine schöne Spalte B",
DataPropertyName = myFunnyDataTable.BColumn.ColumnName
});
Das Ergebnis sind in dem Fall 4 Spalten: "A", "B", "C", "Meine schöne Spalte B".
Lösung für dein Problem
Du solltest dir überlegen, ob du AutoGenerateColumns auf false stellst, dann hast du den kompletten Aufbau der Spalten selbst in der Hand.
Alternativ kannst du auch weiterhin nachträglich die Spalten austauschen, musst dann aber auf die korrekten DataPropertyName achten und vor allem die generierten "Originalspalten" löschen - sonst siehst du doppelt.
Im Anhang gibt es noch ein kleines Bild von einem Beispiel.
Oben links eine DataTable für boolsche Werte, Value (bool) als ValueMember; Desc (string) als DisplayMember.
Oben rechts eine DataTable für erlaubte Zahlwerte, Value (int) als ValueMember/DisplayMember.
In der Mitte meine DataTable mit den Einträgen (Name string, Flag bool, Zahl int) und automatisch generierten Spalten.
Unten die gleiche DataTable, allerdings mit manuell hinzugefügten (ComboBox)Spalten und den jeweils hinterlegten Auswahlkatalogen.
Alle "Länder"...handelt sich in Wirklichkeit nicht um Länder 🙂 stammen also aus dem ViewModel mit einer List<string>.
Die anderen Properties sind doch aber vom Land abhängig, also nimm doch einfach eine Klasse die eben alle zusammengehörigen Informationen enthält.
Dann ist es eben eine List<IrgendeinKlassenName>, damit kannst du dann wunderbar arbeiten. 🙂
Dann ist doch aber nicht das Überschreiben der OnKeyDown-Methode Schuld, sondern die Tatsache, dass das OnKeyDown (über ProcessKeyEventArgs) im TabControl zusätzlich aufgerufen wird. 😁
Wobei wohl nur mein Kopf der überschriebenen Methode die Schuld gegeben hat, du hast das ja so nie gesagt.
Egal, nun ist es zumindest logisch. =)
Ich stelle mir das so vor:
Du hast eine Form mit einer ComboBox mit den Einträgen Deutschland, Schweiz, Österreich.
In den Textboxen werden dazu dann z.B. Adresse, Telefonnummer, E-Mail zum ausgewählten Land angezeigt.
Also hast du ungefähr so eine Klasse:
public class Country
{
public string Name { get; }
public string Address { get; }
public string Telephone { get; }
...
}
Rest siehe pinki. 😁
Das mag ja sein, dass das TabControl OnKeyDown() überschreibt, aber mir erschließt sich das Verhalten immer noch nicht.
Der Code der da drin steckt, wird ja nie erreicht, es sollte nur das base.OnKeyDown() aufgerufen werden, also warum ist das Verhalten anders, als wenn es nicht überschrieben worden wäre?
Für das Fenster z.B. läuft er in das OnKeyDown ja auch nicht rein.
Einfach eine Klasse nutzen?
Ähm, äh, ja. 🤔
Mal davon ab, dass ich persönlich das Verhalten nicht auf das TabControl geschoben hätte,
ist mir auch nicht ganz klar, wie sich das Überschreiben der OnKeyDown-Methode jetzt in das beschriebene Verhalten einfügt.
Es wird ja nur das OnKeyDown des TabControl überschrieben, was allerdings auch nicht aufgerufen werden dürfte - oder irre ich da?
Warum läuft er da rein? 🤔
Hast du meine zweite Antwort beachtet?
Meiner Erinnerung nach ist die Aussage von Stefan.Haegele korrekt, auch wenn ich es gerade nicht erklären kann und auch gerade dazu keinen passenden Artikel im WWW finde. 😁
Stefan, erleuchte uns. 😉
Wird die Datenbankverbindung im Konstruktor aufgebaut?
Wenn ja, kannst du mal mit Hilfe der GetIsInDesignMode-Methode den Aufruf "blockieren" bzw. nur ausführen, wenn das Programm dann tatsächlich läuft.
Kann dir zwar nicht direkt helfen, trotzdem 2 Tipps:
Du hast für das TabControl also auch das KeyDown-Event abonniert?
An welcher Stelle verwendest du dann Model1?
Das wird gerade nicht ersichtlich...
Nutze die Code-Tags des Forums zur besseren Lesbarkeit.
Willst du das Muster jetzt beim Öffnen des Fensters oder beim Button-Klick laden? 🤔
Naja, das ist ein Workaround, ändert allerdings nichts an meiner Aussage.
An ein Event kann man per se kein Command hängen.
Auch das EventToCommand, was Sir Rufo gepostet hat, wird das Command nur mit Hilfe einer weiteren Klasse an das Event anmelden können (schaue mir das EventToCommand gleich mal an).
Du nutzt jetzt ein KeyBinding, was mit dem PreviewKeyUp nichts zu tun hat, auch wenn es so aussieht.
Was es nicht alles gibt. 😉
PreviewTextInput ist ein Event, daher kannst du da kein Command nutzen.
Die 'param =>'-Schreibweise ist nur eine Möglichkeit von vielen. Das RelayCommand möchte eine Action<object> bzw. ein Predicate<object> haben.
Wenn deine Funktionen folgende Signatur haben:
private void StartManuellPrint(object param)
private bool CanStartManuellPrint(object param)
haben, kannst du es so angeben:
new RelayCommand(this.StartManuellPrint, this.CanStartManuellPrint);
Alles was das Programm benötigt, muss auch da sein.
Wenn dein anderes Programm keine Abhängigkeiten hat, dann reicht natürlich die .exe. Gibt es Abhängigkeiten zu anderen DLLs, müssen sie natürlich auch da sein.
Eine Möglichkeit wäre, einfach einen Link auf die .exe im Debug-Ordner anzulegen.
Oder aber alle abhängigen DLLs mit in die .exe zu packen, Stichwort ILMerge. - siehe Abt.
Kopierst du denn nur die .exe?
[FAQ] Programm läuft in anderer Umgebung nicht (richtig)
Moin,
wenn du die Klasse produktiv einsetzt, dann musst du auf jeden Fall nochmal ran:
ConvertFahrenheitToKelvin
ergibt 5 / 9 IMMER 0 (int-Berechnung!), dadurch ist das Ergebnis falschConvertFahrenheitToKelvin
und ConvertKelvinToFahrenheit
273.15 statt 273 nutzen, sonst ist das Ergebnis falschWeiterhin könnte man noch folgende Punkte ändern:
public static double ConvertFahrenheitToKelvin( double fahrenheit )
{
return ( 5 / 9 * ( fahrenheit - 32 ) + 273 );
}
public static double ConvertFahrenheitToKelvin( double fahrenheit )
{
return ConvertCelciusToKelvin(ConvertFahrenheitToCelsius(fahrenheit));
}
oder
public static double ConvertKelvinToFahrenheit( double kelvin )
{
return ( ( ( kelvin - 273 ) * 9 / 5 ) + 32 );
}
public static double ConvertKelvinToFahrenheit(double kelvin)
{
return ConvertCelsiusToFahrenheit(ConvertKelvinToCelcius(kelvin));
}
=)
Ich hätte da auch noch eine Anmerkung/Frage. 😁
Gibt es einen Grund, warum du in dem Bereich die weiteren if-Zweige noch um eine Ebene eingerückt hast?
if ( toreMannschaft == toreGegner ) { fmt = "{0} gleichen aus zum {1}:{2}"; } else { if ( toreMannschaft > toreGegner + 1 ) { fmt = "{0} bauen den Vorsprung aus auf {1}:{2}"; } else if ( toreMannschaft < toreGegner ) { fmt = "{0} holen auf zum {1}:{2}"; } else { fmt = "{0} gehen mit {1}:{2} in Führung"; } }