Hi Herbivore,
das KeyDown-Ereignis erhält die Nachricht, die Eingabetaste sei gedrückt worden, obwohl es in Wirklichkeit ein Mausklick in der AutoComplete-Liste war.
AcceptButton scheidet aus: wir benutzen ComponentOne-Buttons, die nicht als AcceptButton vom Formular anerkannt werden 😭
Was hast Du nicht verstanden?
Beiliegendes Projekt simuliert das Problem doch perfekt?
Gruß
Ron
Du könntest im Tag der TextBox auf das zugehörige Label verweisen.
Im Changed-Ereignis der Textbox aktualisierst Du dann das Label:
((sender as Textbox).Tag as Label).Text = "Mein Text";
Das entbindet Dich aber nicht von der Notwendigkeit, Zuweisungscode für die Tags zu schreiben:
textbox_1.Tag = label_1;
textbox_2.Tag = label_2
...
hth
ron
Hi Folks,
wir wollen das Drücken der Enter Taste in bestimmten Formularen abfangen (bspw. weil ein Assistent zum nächsten Schritt schalten soll o.ä.).
Problem (s. beiliegendes Projekt):
Wenn eine Textboxeine AutoComplete-Liste anbietet, der Benutzer einige Zeichen in das Textfeld eingibt, die Vervollständigungsliste aufgeht und der Benutzer dann mit der Maus eine Auswahl in der Liste trifft entsteht im Control ein Enter-Ereignis.
Das ist doch ein Bug im Framework, oder?
Wie kann ich jetzt noch umgehen, dass das Formular die Enter-Verarbeitung aufnimmt, obwohl ja nur die Listenauswahl in der Textbox eingetragen werden soll?
Danke th
klingt nicht nur logisch, ist es auch: Problem gelöst. 😃
Hi Folks,
in einem Form A überschreibe ich OnKeyUp; insbesondere soll hier Escape das Form A schliessen.
Von Form A aus rufe ich ein OpenFile-Dialog auf:
private void OpenFile()
{
if (openFileDialog.ShowDialog(this) == DialogResult.OK)
{
FileName = openFileDialog.FileName;
...
}
}
Wenn der Benutzer aber die Escape-Taste verwendet, um diesen modalen Dateidialog zu schliessen, wird hinterher zusätzlich noch das OnKeyUp-Ereignis von Form A durchlaufen.
Das führt natürlich dazu, dass sowohl der OpenFileDialog als auch Form A geschlossen werden. 😦
1.Warum ist das so?
Die Escape-Taste sollte vom OpenFileDialog längst als Handled gekennzeichnet sein.
1.Wie kann ich in diesem Fall in OnKeyUp unterscheiden, dass der Sender nicht Form A selbst war? oder 1.Wie kann ich in OpenFile() selbst die Tastaturwarteschlange leeren oder um Escape erleichtern?
Danke für Eure Hilfe
ron
PS: Um es gleich vorwegzunehmen:
Die Eigenschaften CancelButton und AccepptButton des Formulares scheiden für meine Bedürfnisse aus; die Schalter sind Fremdkomponenten, die vom Compiler nicht als gültige Werte dieser Eigenschaften anerkannt werden.
nope,
das führt zu der Fehlermeldung
"child" ist kein untergeordnetes Steuerelement dieses übergeordneten Elements.
wenn man im designer ein steuerelement in das panel platziert.
hi herbivore,
Also das der Designer durcheinander kommt, wenn du so "Schweinereien" machst, wie die Controls-Property zu überschreiben, finde ich mehr oder weniger unausweichlich.
Diese "Schweinerei" hat mir ein von mir hochgeachteter Experte dieses Forums im gleichen Thread vor zwei Jahren vorgeschlagen:
...da du Panels.Controls problemlos überschreiben kannst
Aber vielleicht hast Du deine Meinung ja inzwischen geändert 😉
Wie auch immer: m.E.n. ist es durchaus üblich, das Controls-Property auf ein ChildControl umzuleiten - das sieht man immer mal wieder auf einschlägigen C# Seiten.
Oder kennst Du einen anderen/besseren Weg, das Hinzufügen eines Steuerelements in einen untergeordneten Container des eigentlichen Controls umzuleiten?
Gruß
Ron
hi developerx,
hast du seinerzeit das docking-problem gelöst?
hi zusammen,
ich habe einen Panel-Erben, der in seinem Inneren eine GroupBox darstellt:
public class GroupPanel : Panel
{
#region Members
// Controls
private GroupBox groupBox;
#endregion
#region .ctor(s)
public GroupPanel() : base()
{
SetStyle( ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor, true );
Padding = new Padding(1);
// groupBox
groupBox = new GroupBox();
groupBox.Padding = new Padding(3, 3, 3, 3);
groupBox.Dock = DockStyle.Fill;
groupBox.Name = "groupBox";
groupBox.TabIndex = 0;
groupBox.BackColor = Color.Transparent;
base.Controls.Add(groupBox);
}
#endregion
}
Eingebettete Steuerelemente sollen jetzt in der GroupBox "landen", was zur Überschreibung von Controls führt:
#region Overrides
public virtual new ControlCollection Controls
{
get { return groupBox.Controls; }
}
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
e.Control.BringToFront();
}
#endregion
Mit der Padding-Eigenschaft des Panels wird nun logischerweise der Abstand der eingebetteten GroupBox vom Panel-Außenrand gesteuert.
Ich möchte aber den Abstand der nun in das Control platzierten Elemente zum GroupBox-Rand steuern können.
Hierfür habe ich eine Eigenschaft namens InnerPadding angelegt:
#region Properties
public virtual Padding InnerPadding
{
get { return groupBox.Padding; }
set { groupBox.Padding = value; }
}
#endregion
**Das Problem **:
Lege ich nun bspw. eine Textbox in das Control und docke es bspw. Bottom, wird es in die GroupBox gedockt, berücksichtigt aber das Padding der GroupBox nicht.
Ausserdem bin ich in der Lage, mit dem Designer das innere Steuerelemente aus den Grenzen der GroupBox herauszuziehen, also in den Bereich zwischen Panel-Außenrand und Groupbox - das darf ja eigentlich auch nicht sein.
Ich vermute man könnte das über die Eigenschaft ClientRectangle des Panels steuern, aber die ist ja schreibgeschützt.
Danke für Eure Hilfe
ron
Sieht jemand hier, was ich falsch mache oder nicht berücksichtige?
hi jj
war diese woche beim launch und habe einen vortrag von holger sirtl und jörg jooss zu explizit diesem thema gehört und ein gespräch mit jörg im anschluss geführt.
sehr interessant fand ich das muster pipes and filters.
außerdem regte jörg an, die muster zu vermischen.
so ist es bspw. nicht nur denkbar, sondern oft unbedingt sinnvoll, einen filterknoten durch ein mvc muster zu realisieren.
konkretes beispiel:
aus der datenquelle wird bspw. ein abgeschlossener import gemeldet (import = pipe, ereignismeldung = filter)
der filterknoten für die nächste pipe ist die kontrolle der daten durch einen anwender, der nun ja wieder eine GUI braucht, die als MVC realisiert ist.
die durch den anwender aufbereiteten daten werden in die nächste pipe geschickt, woduch sich wieder ein ereignis ergibt, usw.
s.auch:
Pipes and Filters
ich würde mir auch an deiner stelle den vortrag im web anschauen, sobald die launch vorträge verfügbar sind.
er war am mittwoch den 20. und trug den titel "Entwurf und Aufbau ein er leistungsfähigen Anwendungs architek tur - Schritt für Schritt"
hth
ron
hi 110806
sooooo billig isses ja dann auch wieder nicht.
bei SQL Server / T-SQL funktioniert es so:
SELECT
substring(spalteA, 1, 2),
convert(float, Count(RecordID)) / (select count(RecordID) from myTable where spalteB < 30) as dieEinen,
convert(float, Count(RecordID)) / (select count(RecordID) from myTable where spalteB > 50) as dieAnderen
FROM
myTable
GROUP BY
substring(spalteA, 1, 2)
hth
ron
hey zusammen,
fein, dass sich so kurzfristig dann doch noch ein paar gefunden haben, die lust haben 🙂
außer den hier geposteten interessenten sind wir hier auch schon etwa vier leute aus dem rhein-main gebiet.
da am dienstag die abendveranstaltung schon microsoft-seitig bestritten wird, habe ich jetzt einfach mal für mittwoch abend in der champions bar im marriott hotel ab 19:00 einen tisch für 10 personen auf den namen "citizen.ron" reserviert.
die genaue adresse ist hamburger allee 2-10, oder anders gesagt: auf der anderen straßenseite (= 2 fußminuten) 🙂
wär schön euch dort zu sehen.
hattet ihr alle eher den dienstag angedacht, weil ihr vielleicht am donnerstag gar nicht mehr dabeiseid und mittwoch schon wieder abreist, dann gebt hier oder telefonisch nochmal rückmeldung oder andere vorschläge durch;
für alle fälle und rückfragen hier meine mobilfunknummer:
0172 - 60 10 187
bisdenndann
ron
hallo satanlike,
du kannst auch mit einem hintergrundbild des splitcontainers die buttons nur "malen" und dann das klick-ereignis abfangen und die mausposition auswerten.
hth
ron
hi letitia,
folgende gedanken mögen Dir vielleicht weiterhelfen:
Da du mit OR arbeitest, kann das Erzeugen der WHERE-Klausel ja grundsätzlich alle Spalten mit einem Kriterium belegen, egal ob sie in der Auswahlliste erscheinen oder nicht
Was manche nicht wissen, ist, dass der IN-Operator auch so verwendet werden kann, dass das Kriterium in der Spaltenmenge gesucht wird (nicht der Spaltenwert in der Kriterienmenge):
SELECT
*
FROM
PERSON
WHERE (
'Müller' in (Nachnamen, Suchbegriff, Kuerzel)
)
Das mag für Dich ebenfalls von Nutzen sein.
Außerdem könntest Du mit folgendem Trick die Funktion doch die Spalten ermitteln lassen, welche die Abfrage aus der Tabelle abholt:
SELECT
*
FROM
PERSON
WHERE (
1 = 0
)
Ein solches Konstrukt liefert nur die Spaltenstruktur und (natürlich) keine Daten.
Kostet also quasi keine Zeit.
Dann wüsste die Funktion, um welche Spalten es gehen soll.
hth
ron
hi br
wir haben exakt das gleiche für unsere datengitter gemacht.
da der name der spalte eindeutig ist, haben wir unsere (aktiven) filter in einem dictionary gemerkt, dessen schlüssel eben der spaltenname ist.
enthält das dictionary den spaltennamen, ist für die spalte ein filter gesetzt, anderenfalls nicht.
hth
ron
Hallo zusammen,
sicherlich werden einige von Euch die Gelegenheit nutzen, zum MS VS 2008 Launch Event nach Frankfurt zu fahren (http://www.microsoft.com/germany/aktionen/ready-for-take-off/default.aspx)
Also frag´ ich einfach mal ganz salopp in die Runde, wer denn Lust hat, die Identität hinter seinem Avatar preiszugeben und an einem der Abende (vorzugsweise dann wohl der 19.2.) in gemeinsamer Runde ein paar Bier (oder auch grünen Tee...) zu trinken und (nicht nur) zu fachsimpeln?
Als Heimspieler wüsste ich da ein paar nette gastronomische Einrichtungen in Messenähe...
Gruß
Ron
hi happaLil,
wie genau äußert sich "wird nicht unterstützt" denn?
Die ReferenceEventArgs müssen dort auch bekannt sein.
Kann sein, dass ich mich irre, aber das Eigenschaftenfenster des Designers wird keinen generischen EventHandler unterstützen.
hth
ron
verwendetes Datenbanksystem: SQLServer 2005
In einem (untypisierten) DataSet werden der Tabelle [KONTAKTPERSON] zwei Einträge hinzugefügt. Beide Einträge erhalten im Feld {Nachname} per Codezuweisung den Text "<Neue Kontaktperson>":
public DataRowView CreateContactPerson()
{
DataRowView row = (DataRowView)bindingSources["KONTAKTPERSON"].AddNew();
row["RecordID"] = Guid.NewGuid();
row["fkf_Kontakt"] = RowGuid;
row["fkf_Person"] = Guid.NewGuid();
row["Vollname"] = "<Neue Kontaktperson>";
row["Nachname"] = "<Neue Kontaktperson>";
row["Rolle"] = 0;
row["Postempfaenger"] = true;
row["Geburtstagsbrief"] = false;
return row;
}
Der Benutzer kann über ein Formular die Felder beider Datensätze entsprechend eingeben.
Per Debugger erkenne ich beim Speichern, dass die Tabelle [KONTAKTPERSON] nun zwei Datensätze enthält; die BindingSource hat ein EndEdit() durchgeführt, beide Datensätze sind IsEdit = false, haben den State "Added" und in beiden Sätzen stehen die Angaben des Anwenders.
Generiere ich ein ChangeSet, stehen dort im zweiten Datensatz nur die Werte meiner Methode (also z.B. im Feld Nachname der Text "<Neue Kontaktperson>") und keine einzige Eingabe des Benutzers.
Kann mir das bitte jemand erklären? arrrghhh!!!!
Danke für jeden Tip
ron
ComponentSource ist ja "nur" Redistributor der Originalartikel.
Warum kaufst Du nicht gleich beim Hersteller?
Ich habe meine Komponenten bspw. bei ComponentOne und ADX direkt gekauft.
Die MwSt. fiel bei ComponentOne nicht an.
Bei ADX wurde der Verkauf über ShareIT abgewickelt und wies die Kaufsumme und MwSt. entsprechend in Euro aus.
hth
ron
@herbivore,
danke für deine Meinung.
Ich würde die Diskussion gerne nochmal auf den ursprünglichen Anlass zurücklenken, wann man Properties oder Membervariablen verwendet.
Gegeben sei eine einfache Klasse, die in der Lage ist, ihren Zustand über ein Property "State" zu beschreiben oder verändern zu lassen:
namespace PropertyDiscussion
{
[Flags]
public enum State
{
ReadOnly = 0,
CanEdit = 1,
Editing = 2,
CanSave = 4
}
class Subview
{
private State _State;
public virtual State _State
{
get { return _State; }
set { _State = value; }
}
}
}
Ein ganz typisches Muster (wahrscheinlich nicht nur) bei uns ist nun, dass ausserhalb der Klasse jemand erfahren möchte, dass sich dieser Zustand ändern wird oder geändert hat. Ersteres wird dabei so ausgelegt, dass ggf. die Zustandsänderung verhindert werden kann.
Dazu braucht man Ereignisse und konsequenterweise auch die Ereignisauslöser und der Setter des Property wird entsprechend geändert.
Dann landet man bei folgender Mindestimplementierung:
namespace PropertyDiscussion
{
[Flags]
public enum ViewState
{
ReadOnly = 0,
CanEdit = 1,
Editing = 2,
CanSave = 4
}
public class ViewStateArgs
{
public bool Cancel;
public ViewState OldState;
public ViewState NewState;
public ViewStateArgs(ViewState oldState, ViewState newState)
{
OldState = oldState;
NewState = newState;
Cancel = false;
}
}
public delegate void ViewStateChangeEventHandler(object sender, ViewStateArgs e);
public class Subview
{
#region Members
private ViewState _State = ViewState.CanEdit;
#endregion
#region Properties
public virtual ViewState _State
{
get { return _State; }
set
{
if (_State != value)
{
ViewStateArgs e = new ViewStateArgs(_State, value);
OnStateChanging(e);
if (!e.Cancel)
{
_State = value;
OnStateChanged();
}
}
}
}
#endregion
#region Events
// Ereignisse
public event ViewStateChangeEventHandler StateChanging;
public event EventHandler StateChanged;
// Ereignisauslöser
protected virtual void OnStateChanging(ViewStateArgs e)
{
if (StateChanging != null)
StateChanging(this, e);
}
protected virtual void OnStateChanged()
{
if (StateChanged != null)
StateChanged(this, EventArgs.Empty);
}
#endregion
}
}
Folgende drei Fragen möchte ich nun zur Diskussion stellen: 1.Wenn die (Basis-)Klasse verhindern möchte, dass trotz Zustandsänderung die Ereignisse gefeuert werden, könnte sie statt der Zuweisung State = ... auch die Membervariable benutzen. Ist das eine legitime Vorgehensweise? 1.Wollte eine abgeleitete Klasse ebenfalls die Ereignisse umgehen, könnte die Membervariable als protected deklariert werden oder die Ereignisauslöser überschrieben werden oder der Setter überschrieben werden. Welches hiervon ist die beste Vorgehensweise? 1.Sollten Zustandsänderungen, die mit Ereignissen verknüpft sind, überhaupt die Ereignisse umgehen können?
Danke für Eure Meinungen.
Gruß
ron
@svenson,
hi und danke für diese information.
aber gilt der performance verlust auch für c#? denn der text bezieht sich ja auf java.
hi hulk,
ergänzend zu talla sei noch gesagt, dass der Zugriff auf das Property entscheidend andere Auswirkungen haben kann, wenn selbiges als virtual angelegt und dann von einer erbenden Klasse überschrieben wird.
Um es mal mit Code auszudrücken:
class MyThing
{
private int _Count;
public virtual int Count
{
get { return _Count; }
set { _Count = value; }
}
protected virtual int GetSomeResult()
{
return Count; // würde den Inhalt der abgeleiteten Variablen liefern, also bei MyDerivedThing: 0
return _Count; // würde den Inhalt der hier lokal vorgehaltenen Variablen liefern
}
}
class MyDerivedThing : MyThing
{
public override int Count
{
get { return 0; }
set { }
}
}
Da eine abgeleitete Klasse selbst entscheiden sollte, ob sie Funktionalität der Basisklasse verändert, deklarieren wir bspw. alle Methoden und Properties grundsätzlich als virtuell.
Daher haben wir es uns zur Gewohnheit gemacht, auch in der Klasse selbst nur grundsätzlich auch nur die Properties anzusprechen.
hth
ron
danke für eure meinungen.
🙂
Ein Argument FÜR die Aufteilung, das heute hausintern gefallen ist, wäre Vererbung.
Wenn man eine Klasse per Vererbung erweitern möchte, ist es ein ziemlicher Overhead, eine Bibliothek mit mehreren MB einzubinden, obwohl man nur eine Klasse daraus für die Vererbung benötigt.
Hallo zusammen,
ich würde gerne Eure Meinung bzw. Begründungen hören, wann man wieviele Steuerelemente in wieviele Bibliotheken verteilt.
Bisher sind wir bei uns so vorgegangen, Steuerelemente in thematische Gruppen zusammenzufassen und dann in zwei bis drei DLL´s zu kompilieren.
Nachdem wir ComponentOne angeschafft haben ist uns aufgefallen, dass beinahe für jedes Steuerelement dort eine eigene DLL bereitgestellt wird.
Was sind denn hiervon die Vorteile?
(Eine Lizenzfrage kann es meiner Meinung nach nicht sein)
Danke für Eure Meinung
cr
hallo,
wenn ein Label in einem Container plaziert ist, der deaktiviert wird, graut der Text aus.
Ich würde das gerne verhindern (dabei ist Label nur EIN Beispiel).
Überschreibt man, wie allgemein vorgeschlagen, die Methode OnPaint, erkauft man sich diese Option durch zwei Nachteile:
Kennt von Euch jemand eine andere Möglichkeit?
Grundsätzlich finde ich es auch nicht durchdacht, dass .NET den Text im deaktivierten Zusatnd IMMER ausgraut, unabhängig von der gesetzten ForeColor.
Konsequenter wäre doch:
ForeColor = SystemColors.ControlText -> Standardverhalten
ForeColor = Color.Red -> mein definiertes Verhalten
, oder...?
Danke für alle Tips,
cr
danke herbivore,
diese beiträge klingen nach einem großartigen ansatz, auf den ich selbst wohl nicht gekommen wäre.
ich meld mich dann wieder, wenn beim ausprobieren die nächsten probleme auftauchen... 😉
gruß
cr
Hallo zusammen,
ich möchte in (scrollbaren) Listen von mehreren hundert Elementen ca. drei Texte, ein Image und eine Linie darstellen.
Mein aktueller Ansatz ist ein Control-Erbe, die alle mit DockStyle.Top in ein Panel eingefügt werden.
Die Elemente sollen die Zustände "Aufgeklappt" und "Geschlossen" kennen; im geschlossenen Zustand soll nur die Überschrift sichtbar sein (ähnlich Outlook MailItems, die ja im aufgeklappten Zustand z.B. eine Textvorschau enthalten).
Per Kontextmenü sollen natürlich alle Elemente der Liste ihren Zustand umschalten können und hier liegt der Flaschenhals.
Mein Ansatz ist ein UserPaint und nicht das tatsächliche Einbetten anderer Controls in das Topic (Label, PictureBox), aber ich weiß nicht, welche Methode von Control ich außer Paint überschreiben muss, um die Größe des Controls zu variieren, wenn es seinen Öffnungszustand ändert.
Ändere ich innerhalb der Methode OnPaint die Anweisung Size = new Size(...)
dann kann ich der Anwendung beim Malen zugucken...
Wann werden bspw. die Methoden "SetBoundsCore" bzw. "GetScaledBounds" vom Network aufgerufen? Offensichtlich nicht beim Neuzeichnen.
Nachstehender Code stellt die Klasse des Topic dar:
public class DBTopic : Control
{
#region Members
// lokal
private int index = 0;
// Property values
private int _ClosedSize = 16;
private int _OpenSize = 75;
private eTopicState _TopicState = eTopicState.Closed;
#endregion
#region Properties
public int ClosedSize
{
get { return _ClosedSize; }
set { _ClosedSize = value; }
}
public int OpenSize
{
get { return _OpenSize; }
set { _OpenSize = value; }
}
public eTopicState TopicState
{
get { return _TopicState; }
set
{
_TopicState = value;
Refresh();
}
}
#endregion
#region .ctor
public DBTopic(int i) : base()
{
index = i;
SetStyle(ControlStyles.UserPaint, true);
Dock = DockStyle.Top;
Size = new Size(Width, _ClosedSize);
}
#endregion
}
Nachstehender Code erzeugt die Elemente, ist sehr performant.
for (int i = 0; i < 200; i++)
{
DBTopic p = new DBTopic(i);
dict.Add(i, p);
}
DBTopic[] ar = new DBTopic[200];
dict.Values.CopyTo(ar, 0);
ControlPanel.Controls.AddRange(ar);
Nachstehender Code schaltet alle Elemente in den geöffneten Zustand um:
SuspendLayout();
foreach (DBTopic t in dict.Values)
{
t.TopicState = eTopicState.Open;
}
DBTopic[] ar = new DBTopic[200];
ResumeLayout();
ControlPanel.Refresh();
Nachstehender Code war mein Ansatz, die Größe des Elements von seinem Zustand abhängig zu machen, aber diese Methode wird nur beim Erzeugen des Elements aufgerufen, nicht beim Refresh():
protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
{
if (TopicState == eTopicState.Open)
base.SetBoundsCore(x, y, width, _OpenSize, specified);
else
base.SetBoundsCore(x, y, width, _ClosedSize, specified);
}
Danke für Eure Tips
Gruß
Ron
@LastGentleman
ja, klappt ebenfalls nicht.
direkt nach der serialisierung zu deserialisieren liefert im programmcode exakt den gleichen fehler, im überwachungsfenster aber keinen
ps:
ja, ich habe die aktuellsten servicepacks an allen fronten installiert 😉
Hallo zusammen,
ich lade zur Laufzeit Dimensionen von Steuerelementen aus selbst definierten Settings-Objekten, die in einer Datenbank serialisiert sind.
Dazu gehören bspw. auch SplitterDistances von SplitContainern.
Ich habe aktuell in einer von SplitContainer abgeleiteten Klasse die Methode Refresh() überschrieben, aber beim ersten Refresh ist der Eigentümer des SplitContainer ggf. noch nicht gezeichnet und hat kleinere Dimensionen, als der geladene Wert erfordern würde.
Der Fehler ist dann "SplitterDistance muss zwischen Panel1MinSize und ... liegen".
Welches Ereignis / Methode bietet sich also stattdessen an, die SplitterDistance zu laden?
Danke für Eure Hilfe.
ron
Hallo zusammen,
falls jemand mal in die gleiche Falle läuft, hier also heute die Lösung.
Man deklariere eine Schnittstelle IFoo für Foo und dann gehts 😉
protected internal void LoadSettings(DataRow viewRow)
{
// Read binary settings
if (viewRow["Settings"] != DBNull.Value) try
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream((byte[])viewRow["Settings"]);
object obj = formatter.Deserialize(stream);
if (obj is IViewSettings)
_Settings = (IViewSettings)obj;
}
catch {}
if (_Settings == null)
_Settings = new ViewSettings();
}
PS:
Ich weiß zwar immer noch nicht, woher der Fehler kommt, denn ohne Schnittstelle tritt er immer noch auf, aber so wird zur Laufzeit das Objekt wenigstens als IViewSettings erkannt.
hth
ron
danke herbivore,
aber das ist definitiv nicht so.
ich habe es nach deinem post explizit nochmals probiert:
datenzeile löschen, anwendung starten, anwendung beendet => serialisierung in tabellenzeile und -feld, anwendung erneut gestartet, deserialisierung schlägt fehl.
das objekt ist zwar ein bisschen komplexer, weil es dictionaries enthält, aber dennoch - die exception ist schlicht unerklärlich; im überwachungsfenster kann ich wie gesagt die zuweisung problemlos vornehmen - als codeanweisung kracht sie aber. außerdem hat es irgendwann mal funktioniert.
zur vertiefung hier noch das zu serialisiernde objekt (Ziel des ganzen ist, in der datenbank zu speichern, welche spaltenausblendungen, sortierungen, selektionen & markierungen etc. ein benutzer in einer beliebigen tabellenansicht vorgenommen hat):
using System;
using System.Collections.Generic;
using System.Text;
using CCL.Common;
using System.Windows.Forms;
namespace CAF.Views
{
partial class View
{
// InformationCategorySetting
/// <summary>
/// Category dependant settings
/// </summary>
[Serializable()]
public class InformationCategorySetting : IInformationCategorySetting
{
#region Property-bound members
private Guid _Selection;
private Type _SubviewType;
private eRecordsetView _RecordsetView;
private List<Guid> _HighlightedItems;
private List<String> _HiddenColumns;
public SortedList<int, string> _GroupingColumns;
[NonSerialized]
private ContextMenuStrip _ContextMenuStrip;
#endregion
#region Properties
public Guid Selection
{
get { return _Selection; }
set { _Selection = value; }
}
public Type SubviewType
{
get { return _SubviewType; }
set { _SubviewType = value; }
}
public eRecordsetView RecordsetView
{
get { return _RecordsetView; }
set { _RecordsetView = value; }
}
public List<Guid> HighlightedItems
{
get { return _HighlightedItems; }
set { _HighlightedItems = value; }
}
public List<String> HiddenColumns
{
get { return _HiddenColumns; }
set { _HiddenColumns = value; }
}
public SortedList<int, string> GroupingColumns
{
get { return _GroupingColumns; }
set { _GroupingColumns = value; }
}
public ContextMenuStrip ContextMenuStrip
{
get { return _ContextMenuStrip; }
set {_ContextMenuStrip = value; }
}
#endregion
#region .ctor
// Plain constructor for deserialization
public InformationCategorySetting()
{
_GroupingColumns = new SortedList<int,string>();
_HiddenColumns = new List<String>();
_HighlightedItems = new List<Guid>();
_RecordsetView = eRecordsetView.DataGrid;
}
// Initialization constructor for use in application
public InformationCategorySetting(Type type) : this()
{
_SubviewType = type;
_Selection = Guid.Empty;
}
#endregion
}
// ViewSettings
/// <summary>
/// A class designed for XML Serialization storing user settings of a view
/// </summary>
[Serializable()]
public class ViewSettings
{
#region Public members
public string SelectedCategory;
public Dictionary<string, IInformationCategorySetting> CategorySettings;
#endregion
#region .ctor
// Plain constructor for deserialization
public ViewSettings()
{
SelectedCategory = string.Empty;
CategorySettings = new Dictionary<string, IInformationCategorySetting>();
}
#endregion
}
#region Associated properties
private Dictionary<string, eRecordsetView> _AvailableRecordsetContainers;
public Dictionary<string, eRecordsetView> AvailableRecordsetContainers
{
get { return _AvailableRecordsetContainers; }
set {_AvailableRecordsetContainers = value; }
}
#endregion
}
}
hi svenson,
objektvariable obj liefert beim debuggen als assembly und vollqualifizierten namen exakt das gleiche wie im überwachungsfenster die typdeklaration ViewSettings.
Alles stimmt haargenau überein, inkl. Assemblyversion.
hi svenson,
stimmt, riecht voll danach, aber leider ist dem nicht so.
ich habe sogar schon per explorer-suche nach dem begriff ViewSettings im gesamten Entwicklungspfad gesucht; da ist definitiv nix doppelt deklariert.
hi hans
auch Dir danke, aber leider: nope.
datenzeile gelöscht, anwendung gestartet, in tabelle serialisiert, datensatz da, alles cool, dann deserialisiert, gleiches resultat.
hi alle anderen, 😉
gibt´s noch mehr ideen...?
hi SmEaGoL,
Du könntest das Shown-Ereignis des Formulares verwenden oder überschreiben.
hth
ron
Hallo,
ich habe ein merkwürdiges Phänomen beim Deserialisieren eines Objekts:
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream((byte[])viewRow["Settings"]);
object obj = formatter.Deserialize(stream);
_Settings = (ViewSettings)obj;
Die letzte Zeile wirft die Exception (Das Objekt des Typs ViewSettings kann nicht in Typ ViewSettings umgewandelt werden.
Betrachte ich mir im Debugger aber die Variable obj , dann enthält sie genau diesen Typ (ViewSettings).
Noch verschärfter:
Gebe ich die Anweisung
_Settings = (ViewSettings)obj;
im Überwachungsfenster ein, wirft dieses keinen Fehler und die Variable _Settings ist richtig belegt.
Was übersehe ich hier?
Was macht der ausgeführte Code anders als das Überwachungsfenster?
Thanx vorab
Ron
danke Jürgen,
hatte in der Suche danach wohl nicht die richtigen Stichworte verwendet. 😉
Gruß
Ron
Hallo zusammen,
mich würde interessieren, ob es sich auf das Laufzeitverhalten einer Anwendung im Release-Modus auswirkt, ob ich Exceptions stellenweise in Kauf nehme oder ob es **immer **besser ist, diese zu umgehen.
In folgendem vereinfachten Beispiel wird in einem Getter der Wert einer Tabellenspalte als Zeichenkette zurückgegeben.
Das Problem ist, dass das select-Statement der Datatable eventuell den gesuchten Datensatz nicht findet.
In Implementierung 1 wird der Fehler in Kauf genommen:
string this[string category, byte state]
{
get
{
try
{ return (string)dataTable.Select("Category = '" + category + "'")[0][state]; }
catch
{ return string.Empty; }
}
}
Implementierung 2 umgeht den Fehler in ausführlicher Manier 😉
string this[string category, byte state]
{
get
{
string result = string.Empty;
if (dataTable != null)
{
DataRow[] rows = dataTable.Select("Category = '" + category + "'");
if (rows.Length > 0)
result = (string)rows[0][state];
}
return result; }
}
}
Implementierung 1 wirft zur Laufzeit im Debug Modus im Ausgabefenster der Entwicklungsumgebung jedesmal den Fehler:
Eine Ausnahme (erste Chance) des Typs "System.IndexOutOfRangeException" ist in CAF.Views.dll aufgetreten.
Ist die (sauberere) Implementierung 2 aber im ReleaseModus wirklich besser oder wäre Variante 1 sogar schneller?
Danke für Eure Meinung.
Gruß
Ron
hi fabian,
flackert es immer?
Auch bei ResolveASHyperlink = false?
Flackern tut es bei mir nur, wenn ich ResolveASHyperlink auf True setze (was ich im Augenblick nicht tue, da die Logik für den Aufruf eines aufgelösten Elements auch noch nicht implementiert ist, sondeern nur die Cursor-Anzeige als Hand)
Ich glaube eher, dass OnMouseMove nicht die richtige Methode ist; vielleicht muss man auch hier tiefer in die WINAPI einsteigen.
Aber dazu werde ich selbst in den nächsten zwei Wochen keine Zeit haben.
Gruß
Ron
...und hier ist dieKomponente samt Testprojekt und TestDaten.
Viel Spass damit
Ron
PS:
Es gibt ein noch etwas jungfräuliches Property namens ResolveAsHyperlink.
Idee ist, dass aufgelöste Elemente mit einem Handzeiger versehen werden. Das flackert aber leider ziemlich.
Also wer von Euch Zeit und Lust hat... 😉
So sieht es für den Entwickler aus:
Beschreibung:
Eine RichTextBox, die es erlaubt, in einer zugrundeliegenden Tabelle die eingegebenen Textelemente zu suchen und je nachdem, ob sie gefunden wurden oder nicht, unterschiedlich zu formatieren.
Verwendungszweck
Hintergrund ist, dass man manchmal in einem Eingabefeld Kürzel (für bspw. Mitarbeiter, Abteilungen, Städte, etc.) eingeben möchte.
Man kennt das so ähnlich vom Mailadressfeld einer neuen Nachricht in Outlook.
Damit der Anwender sofort sieht, ob seine Angaben gültig sind, schlägt die RichTextBox diese Elemente nach und formatiert sie (Bild 1) wie vom Entwickler im Designer eingestellt (Bild 2).
Hinweis:
Der Code für die Formatierung stammt aus http://geekswithblogs.net/pvidler/archive/2003/10/15/188.aspx; ich habe das nur ein bisschen für den aktuelle Zweck gekapselt
Schlagwörter: RichTextBox, RichTextBox Formatierung, Formatierung, Nachschlagen
hallo herbivore,
danke für den tip.
inzwischen habe ich einen helden gefunden, der´s schon erledigt hat:
http://geekswithblogs.net/pvidler/archive/2003/10/15/188.aspx
gruß
ron
Hallo zusammen,
was wäre denn der richtige Ansatz um eine geschlängelte Unterstreichung in einer RichTextBox, ähnlich dem Syntaxfehlerhinweis in WinWord hinzukriegen?
Durch FontStyles wird sowas ja nicht angeboten.
Danke für Eure Tips.
ron
hi xpheler
private void myFormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
}
Hallo zusammen,
mit folgendem Code (irgendeines SQLBrokers unseres Frameworks) erzeuge ich eine BindingSource, deren DataTable in einem DataSet liegt, das über "using" angelegt ja eigentlich sofort danach wieder im Nirwana verschwindet:
public BindingSource GetBindingSource(string tableName, string commandText, params object[] parameters)
{
try
{
// Create an adapter and retrieve data
using(SqlDataAdapter dataAdapter = GetDataAdapter(commandText, parameters))
{
using (DataSet dataset = new DataSet())
{
dataAdapter.Fill(dataset, tableName);
return new BindingSource(dataset, tableName);
}
}
}
catch (Exception exc)
{
return null;
}
finally { connection.Close(); }
}
In meiner Anwendung kommt jetzt die BindingSource prima an, ich kann Comboboxen füllen etc. und auch darin navigieren.
Die triviale Frage, die sich mir stellt: wo liegt denn nun die der BindingSource zugrundeliegende Tabelle?
Anders gesagt: Gibt´s das DataSet jetzt in Wirklichkeit noch?
Danke für Eure Hilfe.
Ron
Hi Diver,
um die DLL´s von SQL Express musst Du Dir eigentlich keine Gedanken machen: Du prüfst, ob er installiert ist, und wenn nicht, rufst Du die Installation einfach auf und die hast Du mitgeliefert (obwohl es eigentlich sinnvoller ist, das bei bestehender Internetverbindung dann auch noch darüber abzuwickeln, weil Du Dir dann der aktuellsten Version sicher sein kannst).
Gruß
ron
hi diver
Gibt es vielleicht eine Möglichkeit diese Importfunktion über Interop oder COM anzusprechen ?
per objektmodell lässt sich das, was der assistent macht, auch mit der methode TransferText / TransferSpreadsheet / TransferDatabase des DoCmd-Objekts aufrufen.
Das sollte über Interop also genauso möglich sein.
Der Frage "Muss es denn unbedingt Access sein?" kann ich mich allerdings nur anschliessen 😉
Hi Pro,
ja, das stimmt, für die meisten geht das - leider aber nicht für alle.
Im oben geschilderten Fall (sprich: auf meinem Rechner) bspw. sind der MS CRM Hoster und der iPodService inder Systemstartlasche nicht aufgeführt und auch sonst nicht ohne weiteres zu finden.
Das Projekt ist eben ein schneller Weg, die Dinger loszuwerden, wie er uns als Programmierer eben offen steht - kleine Fingerübung quasi 😉
Hi Golo,
stimmt, das ist eine gute Idee.
und dann am besten als Dienst mit TrayIcon und allem drum und dran...
@alle:
Also, wer mitmachen will...
Beschreibung:
Mich ärgert, dass beim Systemstart von Windows diverse Prozesse gestartet werden, auf die ich gerne verzichte, von denen aber einige gar keine Möglichkeit bieten, per Anwendungseinstellung Ihren Start zu verhindern (Bsp.: HP Softwareupdates für Druckertreiber.
Beiliegendes Konsolenprojekt arbeitet eine in der config-Datei hinterlegten StringList ab und tötet alle dort aufgeführten Prozesse.
Die config-Datei sieht so aus:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="KillProcess.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<KillProcess.Properties.Settings>
<setting name="ProcessList" serializeAs="Xml">
<value>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>iPodService</string>
<string>qttask</string>
<string>FjtwSetup</string>
<string>hpwuSchd</string>
<string>winampa</string>
<string>jusched</string>
<string>iTunesHelper</string>
<string>Microsoft.Crm.Application.Hoster</string>
</ArrayOfString>
</value>
</setting>
<setting name="AutoClose" serializeAs="String">
<value>False</value>
</setting>
</KillProcess.Properties.Settings>
</applicationSettings>
</configuration>
...der gesamte Code ist:
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Collections.Specialized;
using KillProcess.Properties;
namespace KillProcess
{
class Program
{
static void Main(string[] args)
{
StringCollection processList = Settings.Default.ProcessList;
// Willkommensgruß :-)
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("Prozesse werden geprüft...");
Console.WriteLine();
// Prozessliste abarbeiten
foreach (string processName in processList)
{
Process[] processes = Process.GetProcessesByName(processName);
if (processes.Length > 0)
{/*Prozess ist aktiv*/
Console.ForegroundColor = ConsoleColor.White;
Console.Write(" Prozess gefunden: ");
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(processName);
Console.ForegroundColor = ConsoleColor.White;
Console.Write("...");
for (int i = 0; i < processes.Length; i++)
processes[i].Kill();
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("beendet.");
}
else
{/*Hinweis für nicht aktiven Prozess*/
Console.ForegroundColor = ConsoleColor.White;
Console.Write(" Prozess nicht aktiv: ");
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(processName);
}
Console.WriteLine();
} // Prozesslistenschleife
// Ggf. auf Benutzertaste warten
if (!Settings.Default.AutoClose)
{
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine();
Console.WriteLine("Drücken Sie eine Taste um das Fenster zu schließen.");
Console.ReadKey();
}
}
}
}
Schlagwörter: Process, Tools
Viel Spaß damit,
ron