Hallo,
heute zeige ich euch, wie ihr das Mausscrolling in Comboboxen deaktivieren könnt. Dazu ,müsst ihr einfach das MouseWheel-Ereignis behandeln, und die Handled-Eigenschaft auf True setzen (Beachte: das Ereignis ist nur im Code verfügbar, nicht im Eigenschaftenfenster).
Ich habe diese Methode als Extension implementiert:
Dann müsst ihr nur noch diese Methode auf der gewünschten Combobox aufrufen:
Das war es schon :) nun ist das Mausrad in Comboboxen deaktiviert
mfg
Sebastian
Freitag, 30. November 2012
Donnerstag, 29. November 2012
WinForms: Flackern beim Zeichnen von Usercontrols vermeiden
Hallo,
in einem meiner letzten Projekte durfte ich eine große Anwendung mit Winforms umsetzen. Es war eine Anwendung mit einer komplexen UI und einer Menge an Daten, welche strukturell sehr komplex aufgebaut waren. Mit einfachen Controls konnte man die Anforderungen nicht erfüllen, also musste man viele UserControls erstellen.
Nun kommt man in Winforms relativ schnell an den Punkt, dass wenn man mehrere UserControls auf einer UI hat, das man unschöne Paint-Artefakte bekommt. Das schlimmste dürfte schon vielen von euch begegnet sein: Flacken und Flimmern beim Anzeigen der Controls. Ich möchte euch hier meine Lösungen aufzeigen, jenachdem ob es sich um ein einzelnes Controls handelt, oder ob man mehrere UserControls in einem Panel anzeigen möchte (und hier das sichtbare Aufbauen der UserControls verhindern möchte).
Natürlich benötigen wir noch eine Methode um alles wieder zu aktivieren:
Wenn man dann UserControls hinzufügen möchte, sollte man das hinzufügen zwischen die Aufrufe setzen:
Ich hoffe ich konnte euch damit etwas helfen :)
mfg
Sebastian
in einem meiner letzten Projekte durfte ich eine große Anwendung mit Winforms umsetzen. Es war eine Anwendung mit einer komplexen UI und einer Menge an Daten, welche strukturell sehr komplex aufgebaut waren. Mit einfachen Controls konnte man die Anforderungen nicht erfüllen, also musste man viele UserControls erstellen.
Nun kommt man in Winforms relativ schnell an den Punkt, dass wenn man mehrere UserControls auf einer UI hat, das man unschöne Paint-Artefakte bekommt. Das schlimmste dürfte schon vielen von euch begegnet sein: Flacken und Flimmern beim Anzeigen der Controls. Ich möchte euch hier meine Lösungen aufzeigen, jenachdem ob es sich um ein einzelnes Controls handelt, oder ob man mehrere UserControls in einem Panel anzeigen möchte (und hier das sichtbare Aufbauen der UserControls verhindern möchte).
- Flackern bei einzelnen UserControls vermeiden
Das Problem bei den Zeichenanforderungen in WinForms ist das sequentielle Zeichnen. Um dieses Vorgang vor dem Benutzer zu "verheimlichen" können wir uns dder Technik des DoubleBufferings bedienen. Winforms bietet dazu automatische Methoden um DoubleBuffering zu verwenden. Dazu müssen nur ein Paar Styles gesetzt werden.
Das setzen der Styles muss im Konstruktor des jeweiligen UserControls erfolgen, nach dem Aufruf von InitializeComponents()
Weitere Optimierungen kann man durch das Überschrieben von OnPaintBackground erreichen. Da in meinem Projekt das oberer ausgereicht hat, habe ich dafür kein Beispiel. Allerdings findet ihr hier weitere Beispiele. - Artefakte beim Hinzufügen mehrere UserControls zu einem Panel verhindern
- Oft kommt es auch zu unschönen visuellen Effekten, wenn man mehrere UserControls zu einem Panel, zB. TableLayoutPanel oder FlowLayoutPanel hinzufügen möchte. Das liegt daran, dass Winforms alle Controls hintereinander zeichnet und diesen Vorgang vor dem Benutzer nicht verbirgt. Das kann man allerdings erreichen, wenn man ein bisschen mit Windowsmessages arbeitet.
- Zuerst sollte man sich dazu eine Variable anlegen, welche der Message WM_SETREDRAW entspricht. Diese Message werden wir nämlich an und abschlaten. Wir bauen damit eine Methodik nach, die dem BeginUpdate() und EndUpdate() von ListViews entspricht.
- Dann benötigen wir eine Methode, welche die Messages auf einem Control verändert. Ich habe diese Methoden als Extensions implementiert:
- Und natürlich eine Methode, welche nach der Arbeit die Messages wieder aktiviert:
- Um nun die Artefakte zu verhindern, wenn man viele UserControls einem TableLayoutPanel hinzuzufügen, sollte man SuspendMessage und SuspendLayout auf dem Panel aufrufen, bevor man die Controls hinzufügt. Dafür habe ich mir auch noch eine Extension geschrieben:
Natürlich benötigen wir noch eine Methode um alles wieder zu aktivieren:
Wenn man dann UserControls hinzufügen möchte, sollte man das hinzufügen zwischen die Aufrufe setzen:
Ich hoffe ich konnte euch damit etwas helfen :)
mfg
Sebastian
Montag, 26. November 2012
SharePoint: Alle aktiven Eventreceiver im Überblick
Hallo,
wer kennt es denn nicht; man entwickelt Eventreceiver für SharePoint und will diese testen. Nun hat man nicht immer die perfekte Umgebung, der Debugger springt nicht rein oder sonstiger Ärger. Oft liegt der Fehler daran, dass ein Eventreceiver nicht richtig an eine Liste gehängt wurde. Gründe kann es dafür viele geben (vergessen dem Feature hinzuzufügen, Feature nicht aktiviert etc.). Mit meinem Fundstück seht ihr schnell, welche Eventreceiver an einer Liste hängen. Da es eine normale Windowsapplikation ist, geht dies alles recht einfach und schnell. Es funktioniert für SharePoint 2007 und 2010, für 2013 hab ich noch keine Kentniss.
Also schaut euch den EventReceiver-Manager ruhig einmal an :)
mfg
Sebastian
wer kennt es denn nicht; man entwickelt Eventreceiver für SharePoint und will diese testen. Nun hat man nicht immer die perfekte Umgebung, der Debugger springt nicht rein oder sonstiger Ärger. Oft liegt der Fehler daran, dass ein Eventreceiver nicht richtig an eine Liste gehängt wurde. Gründe kann es dafür viele geben (vergessen dem Feature hinzuzufügen, Feature nicht aktiviert etc.). Mit meinem Fundstück seht ihr schnell, welche Eventreceiver an einer Liste hängen. Da es eine normale Windowsapplikation ist, geht dies alles recht einfach und schnell. Es funktioniert für SharePoint 2007 und 2010, für 2013 hab ich noch keine Kentniss.
Also schaut euch den EventReceiver-Manager ruhig einmal an :)
mfg
Sebastian
Dienstag, 20. November 2012
SharePoint: Listen eindeutig per JavaScript über die ListUrl identifizieren
Hallo Leute,
da ich mich aktuell in meinem SharePoint-Projekt mit einem Problem herumschlagen musste, welches dem Einen oder Anderem auch begegnet sein wird, wollte ich euch meine Lösung nicht vorenthalten.
Ich musste einen CustomRibbon-Button aktivieren/deaktivieren, jenachdem welche Liste auf einer Website aktiviert ist. Dabei können auf einer Website mehrere Listen per XsltListViewWebpart vorhanden sein. Dabei darf der Button aber nur für spezielle Listen aktiviert werden, für andere wiederrum nicht. Eine Lösung bleibt hier nur über JavaScript, wenn man keine Postbacks möchte. Wichtig ist hierbei, dass man mit der Lösung Listen unabhängig von ihrem DisplayName identifizieren kann.
Dazu muss man seinem SharePoint-Projekt als erstes ein leeres Element hinzufügen:
Danach definiert man in der Elements.xml eine CustomAction, dabei ist zu beachten, dass man den RegistrationType auf ContentType setzt, und die RegistrationId auf 0x01. Damit registriert man den Button für alle Typen.
Danach kommt die Definition der CustomAction (seht ihr gleich). Da wir JavaScript benötigen, müssen wir als nächstes den Layouts-Ordner hinzufügen (bei mir ausgegraut, da ich diesen schon dem Projekt hinzugefügt hatte):
Danach legen wir in diesem Ordner eine .js-File mit unserer Logik an.
Nun müssen wir, damit die entsprechende File auch geladen wird, noch eine weitere CustomAction am Ende unserer Elements.xml anlegen:
Ok, damit sind alle Vorbereitungen getroffen...wichtig für das Aktivieren/Deaktivieren des Buttons ist die Eigenschaft: EnabledScript im UIHandler der CustomAction. Diese Eigenschaft setzen wir durch die Logik in unserer JS-Datei, hier die Zuweisung:
Okay, nun sollten wir uns die Methode: moreThanOneEnabled() anschauen, denn der Rückgabewert dieser Methode bestimmt, ob der Button aktiviert oder deaktiviert ist. Diese Methode muss in unser JS-File (die wichtigsten Stellen sind kommentiert):
In dieser Methode holen wir uns zuerst die Guid der selektierten Liste. Danach schauen wir, ob wir eine andere Liste gewählt haben (die aktuelle Guid speichern wir in der globalen Variablen listId, welche ausserhalb definiert wurde). Wenn wir eine neue haben, dann holen wir uns den Context, und laden asynchron die DefaultViewUrl. Wenn diese Methode erfolgreich ausgeführt wurde, rufen wir onSuccessMethod auf (zeige ich euch gleich). In dieser Methode holen wir uns dann die URL. Weiterhin setzen wir result auf NULL, damit bei einer neuen Liste der Button erstmal wieder deaktiviert wird, solang wir nicht wissen, ob es eine Liste ist, welche wir benötigen.
Danach schauen wir, ob die globale Variable result gesetzt wurde (diese wird in der onSuccessMethode gesetzt, wenn wir eine Liste gefunden haben, für welche wir den Button einblenden wollen, oder wenn eine neue Liste gewählt wurde). Wenn result null ist, geben wir false zurück. Sollte result NICHT null sein, prüfen wir, ob in der aktuellen Liste auch Elemente gewählt wurden, und geben TRUE zurück, wenn result TRUE ist, und Elemente gewählt wurden. Sonst geben wir FALSE zurück.
Schauen wir uns nun die onSuccessMethode an, in der wir die Bedingungen festlegen, ob wir eine Liste haben, für die wir den Button aktivieren wollen oder nicht. In meinem Beispiel wird der Button für eine Liste, welche intern "MeineListe" heisst, aktiviert, für alle anderen deaktiviert. Dabei ist es egal, wie die Liste über die UI benannt wurde. Weiterhin sind man in diesem Code auch die benötigten globalen Variablen:
In dieser Methode holen wir uns als erstes die DefaultViewUrl, diese wurde durch context.Load(list, 'DefaultViewUrl') in moreThanOneEnabled() geladen. Danach untersuchen wir die URL nach dem Namen der Liste, mit der sie angelegt wurde (denn dieser ändert sich nie, egal wie die Liste danach benannt wird). Dann kommen unsere Bedingungen, in denen wir dann result entsprechend setzen. True damit der Button aktiviert ist, false zum deaktiviren.
Als letztes rufen wir RefreshComnmandUI() auf, dies führt dazu, dass moreThanOneEnabled() ein weiteres aufgerufen wird, und somit die entsprechenden result-Werte an EnabledScript zugewiesen werden.
Ich hoffe ich konnte euch damit ungefähr zeigen, wie man mit dem JS-ClientObjectModel arbeiten kann und Listen eindeutig identifiziert. Bis zum nächsten mal ;)
mfg
Sebastian
da ich mich aktuell in meinem SharePoint-Projekt mit einem Problem herumschlagen musste, welches dem Einen oder Anderem auch begegnet sein wird, wollte ich euch meine Lösung nicht vorenthalten.
Ich musste einen CustomRibbon-Button aktivieren/deaktivieren, jenachdem welche Liste auf einer Website aktiviert ist. Dabei können auf einer Website mehrere Listen per XsltListViewWebpart vorhanden sein. Dabei darf der Button aber nur für spezielle Listen aktiviert werden, für andere wiederrum nicht. Eine Lösung bleibt hier nur über JavaScript, wenn man keine Postbacks möchte. Wichtig ist hierbei, dass man mit der Lösung Listen unabhängig von ihrem DisplayName identifizieren kann.
Dazu muss man seinem SharePoint-Projekt als erstes ein leeres Element hinzufügen:
Danach definiert man in der Elements.xml eine CustomAction, dabei ist zu beachten, dass man den RegistrationType auf ContentType setzt, und die RegistrationId auf 0x01. Damit registriert man den Button für alle Typen.
Danach kommt die Definition der CustomAction (seht ihr gleich). Da wir JavaScript benötigen, müssen wir als nächstes den Layouts-Ordner hinzufügen (bei mir ausgegraut, da ich diesen schon dem Projekt hinzugefügt hatte):
Danach legen wir in diesem Ordner eine .js-File mit unserer Logik an.
Nun müssen wir, damit die entsprechende File auch geladen wird, noch eine weitere CustomAction am Ende unserer Elements.xml anlegen:
Ok, damit sind alle Vorbereitungen getroffen...wichtig für das Aktivieren/Deaktivieren des Buttons ist die Eigenschaft: EnabledScript im UIHandler der CustomAction. Diese Eigenschaft setzen wir durch die Logik in unserer JS-Datei, hier die Zuweisung:
Okay, nun sollten wir uns die Methode: moreThanOneEnabled() anschauen, denn der Rückgabewert dieser Methode bestimmt, ob der Button aktiviert oder deaktiviert ist. Diese Methode muss in unser JS-File (die wichtigsten Stellen sind kommentiert):
In dieser Methode holen wir uns zuerst die Guid der selektierten Liste. Danach schauen wir, ob wir eine andere Liste gewählt haben (die aktuelle Guid speichern wir in der globalen Variablen listId, welche ausserhalb definiert wurde). Wenn wir eine neue haben, dann holen wir uns den Context, und laden asynchron die DefaultViewUrl. Wenn diese Methode erfolgreich ausgeführt wurde, rufen wir onSuccessMethod auf (zeige ich euch gleich). In dieser Methode holen wir uns dann die URL. Weiterhin setzen wir result auf NULL, damit bei einer neuen Liste der Button erstmal wieder deaktiviert wird, solang wir nicht wissen, ob es eine Liste ist, welche wir benötigen.
Danach schauen wir, ob die globale Variable result gesetzt wurde (diese wird in der onSuccessMethode gesetzt, wenn wir eine Liste gefunden haben, für welche wir den Button einblenden wollen, oder wenn eine neue Liste gewählt wurde). Wenn result null ist, geben wir false zurück. Sollte result NICHT null sein, prüfen wir, ob in der aktuellen Liste auch Elemente gewählt wurden, und geben TRUE zurück, wenn result TRUE ist, und Elemente gewählt wurden. Sonst geben wir FALSE zurück.
Schauen wir uns nun die onSuccessMethode an, in der wir die Bedingungen festlegen, ob wir eine Liste haben, für die wir den Button aktivieren wollen oder nicht. In meinem Beispiel wird der Button für eine Liste, welche intern "MeineListe" heisst, aktiviert, für alle anderen deaktiviert. Dabei ist es egal, wie die Liste über die UI benannt wurde. Weiterhin sind man in diesem Code auch die benötigten globalen Variablen:
In dieser Methode holen wir uns als erstes die DefaultViewUrl, diese wurde durch context.Load(list, 'DefaultViewUrl') in moreThanOneEnabled() geladen. Danach untersuchen wir die URL nach dem Namen der Liste, mit der sie angelegt wurde (denn dieser ändert sich nie, egal wie die Liste danach benannt wird). Dann kommen unsere Bedingungen, in denen wir dann result entsprechend setzen. True damit der Button aktiviert ist, false zum deaktiviren.
Als letztes rufen wir RefreshComnmandUI() auf, dies führt dazu, dass moreThanOneEnabled() ein weiteres aufgerufen wird, und somit die entsprechenden result-Werte an EnabledScript zugewiesen werden.
Ich hoffe ich konnte euch damit ungefähr zeigen, wie man mit dem JS-ClientObjectModel arbeiten kann und Listen eindeutig identifiziert. Bis zum nächsten mal ;)
mfg
Sebastian
Sonntag, 18. November 2012
Officedokumente per C#-Teil 3: Dokumente kopieren
Hallo,
um die Serie gleich weiterzuführen folgt hier der 3te Teil, die anderen Artikel findet ihr hier:
Teil 1: Dokumente lesen
Teil 2: In Dokumente schreiben
Das kopieren von Dokumenten mit OpenXML ist recht einfach. Man muss dazu nur das Dokument in einen Stream laden, und diesen Stream öffnen. Der folgende Code zeigt das: es wird ein Dokument geöffnet, kopiert, in die Kopie etwas eingefügt und am Ende die Kopie gespeichert. Die eingefügten Elemente sind dabei nur in der Kopie vorhanden.
Wie man sieht ist dazu nicht viel Code notwendig. Das Einfügen von Elementen wird hier durch den Methodenaufruf "AddImageToBody(...)" symbolisiert. Wie diese Methode aussieht, könnt ihr euch in Teil 2 der Serie anschauen.
Ich hoffe ich konnte euch wieder eine kleine Hilfe sein :) bis zum nächsten Mal.
mfg
Sebastian
um die Serie gleich weiterzuführen folgt hier der 3te Teil, die anderen Artikel findet ihr hier:
Teil 1: Dokumente lesen
Teil 2: In Dokumente schreiben
Das kopieren von Dokumenten mit OpenXML ist recht einfach. Man muss dazu nur das Dokument in einen Stream laden, und diesen Stream öffnen. Der folgende Code zeigt das: es wird ein Dokument geöffnet, kopiert, in die Kopie etwas eingefügt und am Ende die Kopie gespeichert. Die eingefügten Elemente sind dabei nur in der Kopie vorhanden.
Wie man sieht ist dazu nicht viel Code notwendig. Das Einfügen von Elementen wird hier durch den Methodenaufruf "AddImageToBody(...)" symbolisiert. Wie diese Methode aussieht, könnt ihr euch in Teil 2 der Serie anschauen.
Ich hoffe ich konnte euch wieder eine kleine Hilfe sein :) bis zum nächsten Mal.
mfg
Sebastian
Officedokumente per C#-Teil 2: In Worddokumente schreiben
Hallo,
Teil 1: Officedokumente per C#-Teil 1
nach längerer Pause geht es nun erstmal mit einem Thema weiter, was ich relativ häufig benötige: schreiben in Word-Dokumente über das OpenXML-Format.
Wie man Dokumente auslesen kann, findet Ihr in Teil 1.
Ich zeige euch im folgendem Code, wie man ein Bild nach einer Textmarke einsetzen kann. Das macht immer dann Sinn, wenn die Position im Dokument variabel sein soll. Ich benutze hier ein Bild, da dies der komplexeste Anwendungsfall ist, die Herangehensweise ist aber analog auch zu Text und anderen Elementen.
So, ok, also erstmal die Methode zum Öffnen des Worddokumentes:
Der Aufruf kann zB so erfolgen:
So und hier die interessanteste Methode, nämlich die, die die Bildreferenz erzeugt, sodass die Binärdaten auch dargestellt werden:
Hier sieht man am Ende auch, wie man eine Textmarke suchen kann, und wie man danach das Bild einsetzt. Natürlich kann man da auch Text oder andere Elemente einfügen.
Ich hoffe ich konnte euch ein kleines bisschen helfen, und freue mich schon auf die nächsten Teile.
mfg
Sebastian
Teil 1: Officedokumente per C#-Teil 1
nach längerer Pause geht es nun erstmal mit einem Thema weiter, was ich relativ häufig benötige: schreiben in Word-Dokumente über das OpenXML-Format.
Wie man Dokumente auslesen kann, findet Ihr in Teil 1.
Ich zeige euch im folgendem Code, wie man ein Bild nach einer Textmarke einsetzen kann. Das macht immer dann Sinn, wenn die Position im Dokument variabel sein soll. Ich benutze hier ein Bild, da dies der komplexeste Anwendungsfall ist, die Herangehensweise ist aber analog auch zu Text und anderen Elementen.
So, ok, also erstmal die Methode zum Öffnen des Worddokumentes:
Der Aufruf kann zB so erfolgen:
So und hier die interessanteste Methode, nämlich die, die die Bildreferenz erzeugt, sodass die Binärdaten auch dargestellt werden:
Hier sieht man am Ende auch, wie man eine Textmarke suchen kann, und wie man danach das Bild einsetzt. Natürlich kann man da auch Text oder andere Elemente einfügen.
Ich hoffe ich konnte euch ein kleines bisschen helfen, und freue mich schon auf die nächsten Teile.
mfg
Sebastian
Es geht endlich weiter
Hallo,
so nach langer Zeit nun endlich wieder mal ein neuer Eintrag. Der Wahnsinn .net hat mir nicht viel Zeit gelassen ;)
Aber nun wird es wieder regelmäßig interessantes und hoffentlich nützliches für euch geben. Also seit gespannt =)
mfg
Sebastian
so nach langer Zeit nun endlich wieder mal ein neuer Eintrag. Der Wahnsinn .net hat mir nicht viel Zeit gelassen ;)
Aber nun wird es wieder regelmäßig interessantes und hoffentlich nützliches für euch geben. Also seit gespannt =)
mfg
Sebastian
Abonnieren
Posts (Atom)





















