Archiv für die Kategorie Tipps and Tricks
Application.OnIdle equivalent for WPF
Veröffentlicht von cplussharp in .net, Tipps and Tricks am 2011-07-01
If you need an alternativ to the WinForms Application.OnIdle event in WPF you can use the DispatcherTimer.
DispatcherTimer timer = new DispatcherTimer(DispatcherPriority.ApplicationIdle); timer.Tick += (s, e) => { // Do something }; timer.Start();
Do you only need the function executet once on idle you use BeginInvoke with Priority Idle.
Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => { // Do something }), DispatcherPriority.ApplicationIdle);
If you don’t like the lambda-style you can also write this:
Dispatcher.CurrentDispatcher.BeginInvoke((Action)doSomething, DispatcherPriority.ApplicationIdle);
Here doSomething needs to be a void function without parameters.
Horziontal Rule in WinForms
Veröffentlicht von cplussharp in Tipps and Tricks am 2011-05-03
Sometime you need a horizontal rule in your WinForms dialog, like the HTML <hr> element. In MFC you have done it with a Static and in WinForms you do it with the equivalent to it, the Lable. First you need to empty the Text of the Label and set the BorderStyle to “Fixed3D”. To set a Witdh or Hight you need to set AutoSize to false. Then you set a Height of 2 and a Width of e.g. 100 and see you have a horizontal rule. If you set the Height to 3 or 4, you can also change the BackColor and get a colorfull version of your horizontal rule. The same applies to a vertical rule, you only swap Width and Height.
jQuery Tablesorter Pager: Jump to Page
Veröffentlicht von cplussharp in Tipps and Tricks am 2011-03-18
This is my first blog in english, so sorry for any spelling errors.
In one of our projects, we use the great jQuery library. A very cool plugin for jQuery is the tablesorter and the extsion to this, the pager. The only disadvantage of the pager plugin is the missing function “Jump To Page”. You can only display the current page and the page count as one string. So i have modified the code of the pager plugin a little, to add this function.
It is a very simple extension, only two existing functions need to be updated. To identify the input-field for the current page and the div for the pagecount, i added two new properties to the settings: cssPageCurrent and cssPageCount. The first function to update is the constructur. Here i connect to the change-event of the input-field and call the moveToPage function. The second function is named updatePageDisplay. It is responsible to update the number in the currentpage-inputfield if you navigate with the next/prev buttons.
Here are the updated functions:
function updatePageDisplay(c, table) { var txt = (c.page + 1) + c.seperator + c.totalPages; var pd = $(c.cssPageDisplay, c.container) if (pd.is("input")) pd.val(txt); else pd.text(txt); var pcur = $(c.cssPageCurrent, c.container) if (pcur.is("input")) pcur.val(c.page + 1); else pcur.text(c.page + 1); var pcount = $(c.cssPageCount, c.container) if (pcount.is("input")) pccount.val(c.totalPages); else pcount.text(c.totalPages); $(table).trigger("tableSorterPagerUpdatePageDisplay"); } this.defaults = { size: 10, offset: 0, page: 0, totalRows: 0, totalPages: 0, container: null, cssNext: '.next', cssPrev: '.prev', cssFirst: '.first', cssLast: '.last', cssPageDisplay: '.pagedisplay', cssPageSize: '.pagesize', cssPageCount: '.pagecount', cssPageCurrent: '.pagecurrent', seperator: "/", positionFixed: true, appender: this.appender }; this.construct = function (settings) { return this.each(function () { ... $(config.cssPageCurrent, pager).change(function () { var c = table.config; var p = $(this).val(); if (p != c.page + 1) { p = parseInt(p) - 1; if (p < 0 || isNaN(p)) p = 0; else if (p > c.totalPages - 1) p = c.totalPages - 1; c.page = p; moveToPage(table); } return false; }); }); };
Here you can download the changed scriptfile: jquery.tablesorter.pager.js
And here is how i used it:
<html> <head> <script type="text/javascript"> $(document).ready(function () { ... $(".tblSortable").tablesorter(); $(".tblSortable").tablesorterPager({ container: $("#pager"), positionFixed: false, size: 30 }); ... }); </script> </head> <body> ... <div id="pager" align="center"> <input type="text" name="pagecurrent" class="pagecurrent"> <span> / </span> <span class="pagecount">1</span> </div> ... <table class="tblSortable"> ... </table> </body> </html>
gemanagte Referenzen in einer nicht gemanagten Klasse speichern
Veröffentlicht von cplussharp in Tipps and Tricks am 2011-01-03
Wenn man C++ CLI und normales C++ in einem Projekt zusammen einsetzt, tauchen früher oder später scheinbar unlösbare Probleme auf. Bei einem Videoplayer den wir zur Zeit programmieren, war es nun soweit.
Um den Programmcode etwas zu entschlacken und den darunter liegenden Algorithmus zur Erstellung eines DirectShow Aufnahmegraphen wieder sichtbar zu machen, wurde es endlich Zeit eine Referenz auf ein gemanagtes Objekt in einer nativen Klasse zu speichern.
Im WPF-Frontend (C#) stellt der Nutzer ein, von welcher Kamera er aufnehmen will und in welches Format das geschehen soll. Diese Konfiguration wird an das Backend (C++) übergeben, in dem schließlich der Aufnahmegraph aufgebaut wird. Dabei kann es sehr viele unterschiedliche Kombination der Konfigurationsparameter geben. Die Art der Kamera (DV, USB, …), die Audioquelle, TimeShift (darüber werde ich bei Gelegenheit auch noch einen Blog-Eintrag schreiben => das war meine Diplomarbeit!) und noch einige mehr spielen hierbei eine Rolle.
Der Aufbau des Aufnahmegraphen erfolgte in einer großen Klasse mit etlichen Funktionen, und immer wieder wurde als Parameter dieser Funktionen ein Parameter vom Typ ICaptureConfiguration^ übergeben. Also habe ich das ganze aufgeflochten und in mehrere Klassen verteilt. Eine abstrakte Basisklasse mit statischen Hilfsfunktionen und einem Interface mit den wichtigsten Methoden, welche dann durch die Detail-Klassen abgedeckt sein müssen. Und um nicht ständig die Konfiguration als Parameter übergeben zu müssen, wird dieser Kontraktur als Member gespeichert.
Doch oh Schreck, was ist das: “Der Typ ICaptureConfiguration^ kann nicht als Membervariable einer nicht C++ CLI Klasse verwendet werden!” Ist ja eigentlich auch logisch, wie soll sonst der Speichermanager der CLR mitbekommen, wann die Referenz nicht mehr gebraucht wird und er das Objekt wieder freigeben kann. Oder noch schlimmer, wenn der Speichermanager des Objekt in seinem Speicher an eine andere Adresse schiebt um Platz zu schaffen, wäre die Referenz plötzlich ungültig! Es gibt nun nur zwei Möglichkeiten: entweder alles auf C++ CLI umstellen, was mindesten 100 Tage oder mehr dauern würde oder aber doch einen Weg finden, die Referenz zu speichern.
Dank google, der MSDN und anderen Seiten ist es mir zum Glück schließlich doch gelungen die Referenz zu speichern. Genau dafür gibt es nämlich das Template gcroot<T>. Es sorgt dafür, dass die zugewiesene Referenz immer erreichbar ist. Da man solch eine Referenz immer mit delete wieder freigeben müsste, ist es besser man nutzt auto_gcroot<T>. Das wird nämlich wie alle Wrapper dieser Art automatisch freigegeben. Im Code sieht das ganze dann in etwa so aus:
#include <msclr\auto_gcroot.h> #using <mscorlib.dll> using namespace System; ... class CCaptureMgrBase { CCaptureMgrBase(ICaptureConfiguration^ captureConfig) { m_captureConfig = captureConfig; } ... msclr::auto_gcroot<ICaptureConfiguration^> m_captureConfig; }
Mit –> kann man nun ganz normal auf die Referenz zugreifen und Funktionen aufrufen.
Eine kleine Anmerkung habe ich allerdings noch. Man kann m_captureConfig nicht mehr einfach so an eine Funktion übergeben, welche ein ICaptureConfiguration^ als Parameter erwarte! Dafür muss man nun m_captureConfig.get() aufrufen.
class CCaptureMgrBase { ... void Render() { // geht nicht: CCaptureMgrBase::Helper(m_captureConfig); // so ist es richtig CCaptureMgrBase::Helper(m_captureConfig.get()); } static void Helper(ICaptureConfiguration^ captureConfig) { ... } }