Laden...

Forenbeiträge von Astrix Ingesamt 12 Beiträge

04.04.2013 - 19:40 Uhr

Hi,

ich habe in einer WPF-Anwendugn eine Klasse "ButtonModern" die von "Button" ableitet.

In dieser Klasse erweitere ich die Basisklasse "Button" u.a. um eine DependencyProperty "IconScale".

Den Wert aus "IconScale" möchte ich in einer RenderTransform des ContentPresenters in meinem Style verwenden und dachte zunächst ich könnte einfach mit TemplateBinding auf den Wert meiner Property zugreifen. Dies habe ich so gemacht:


    <Style TargetType="Controls:ButtonModern">
       <Setter Property="IconScale" Value="0.1" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Controls:ButtonModern">
                    <Grid Background="{TemplateBinding Property=Background}">
                        <Grid Margin="8">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="False" RenderTransformOrigin="0.5,0.5">
                                <ContentPresenter.Effect>
                                    <DropShadowEffect Opacity="0.5"/>
                                </ContentPresenter.Effect>
                                <ContentPresenter.RenderTransform>
                                   <ScaleTransform ScaleX="{TemplateBinding Property=IconScale}" ScaleY="{TemplateBinding Property=IconScale}"/>        
                        </ContentPresenter.RenderTransform>
                            </ContentPresenter>
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Allerdings scheint das TemplateBinding in diesem Fall nicht zu funktionieren, da die Scale immer "1" ist.

Wende ich hingegen ein Binding mit RelativeSource TemplatedParent an funktioniert es:


    <Style TargetType="Controls:ButtonModern">
       <Setter Property="IconScale" Value="0.1" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Controls:ButtonModern">
                    <Grid Background="{TemplateBinding Property=Background}">
                        <Grid Margin="8">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="False" RenderTransformOrigin="0.5,0.5">
                                <ContentPresenter.Effect>
                                    <DropShadowEffect Opacity="0.5"/>
                                </ContentPresenter.Effect>
                                <ContentPresenter.RenderTransform>
                                    <ScaleTransform ScaleX="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IconScale}" ScaleY="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IconScale}"/>   
                             </ContentPresenter.RenderTransform>
                            </ContentPresenter>
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Meine Frage ist nun warum die Variante mit dem TemplateBinding nicht funktioniert? Ich meine, bei dem umschließenden Grid funktioniert das TemplateBinding für den Background ja schließlich auch?

EDIT: was mir eben noch aufgefallen ist: obwohl das Beispiel 2 funktioniert, meldet Visual Studio beim Starten im Direktfenster den folgenden Fehler:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=IconScale; DataItem=null; target element is 'ScaleTransform' (HashCode=13842929); target property is 'ScaleX' (type 'Double')

Vielen Dank für alle Antworten im voraus,
Astrix

06.03.2013 - 22:18 Uhr

Hallo,

zunächst mal möchte ich eine Beispielklasse aus VB.NET zeigen:


Imports SharpDX.WIC

Public Class ResourceFactory
    Implements IDisposable

    Private _ImagingFactory As New ImagingFactory

#Region "IDisposable Support"
    Private disposedValue As Boolean ' So ermitteln Sie überflüssige Aufrufe

    ' IDisposable
    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: Verwalteten Zustand löschen (verwaltete Objekte).
            End If

            ' TODO: Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalize() unten überschreiben.
            ' TODO: Große Felder auf NULL festlegen.
        End If
        Me.disposedValue = True
    End Sub

    ' TODO: Finalize() nur überschreiben, wenn Dispose(ByVal disposing As Boolean) oben über Code zum Freigeben von nicht verwalteten Ressourcen verfügt.
    'Protected Overrides Sub Finalize()
    '    ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(ByVal disposing As Boolean) Bereinigungscode ein.
    '    Dispose(False)
    '    MyBase.Finalize()
    'End Sub

    ' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster richtig zu implementieren.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(disposing As Boolean) Bereinigungscode ein.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class

ImagingFactory ist ein Objekt aus der SharpDX Bibliothek und die Region "IDisposable Support" fügt Visual Studio selbstständig inkl. der Kommentare so ein wenn man IDisposable in seiner Klasse implementiert.

ImagingFactory aus SharpDX stellt einen Dispose-Aufruf bereit, aber wie muss ich in dem Zusammenhang denn nun die von Visual-Studio hinzugefügten Kommentare verstehen:

Da SharpDX ein Wrapper für native COM-Interfaces ist, ist mir nun nicht klar ob ich das _ImagingFactory.Dispose in dem ToDo für verwaltete oder für unverwaltete Objekte (mit überschreiben von Finalize) schreiben muss.

Ich würde nun tippen das ich Finalize überschreiben muss und das Dispose in dem ToDo für unverwaltete Ressourcen unterbringen muss, aber trotz längerer Suche im Internet bin ich mir da unklar.

Mag mir da jemand ein paar Erklärungen zu schreiben?

Vielen Dank für alle Antworten im voraus,
Astrix

15.02.2013 - 01:34 Uhr

Hi,

ich habe eine spezielle Frage aus Interesse und weiß darum nicht so recht wonach ich suchen könnte und wie ich den Beitragstitel hätte wählen sollen.

Zunächst hier mal ein Beispielcode:

                    
                    // Beispiel A:
                    for(int i = 0; i < 1000; i++)
                    {
                        // ...tue etwas...
                        int x = tue_etwas.Result * i;
                        // ...tue etwas mit x...
                    }

                    // Beispiel B:
                    int x;
                    for (int i = 0; i < 1000; i++)
                    {
                        // ...tue etwas...
                        x = tue_etwas.Result * i;
                        // ...tue etwas mit x...
                    }

Im Beispiel A habe ich die int-Variable x im Inner-Scope der Schleife i deklariert.

Im Beispiel B habe ich die int-Variable x hingegen vor der Schleife i deklariert.

Meine Frage ist nun:

Wird im Beispiel A in C# bei jedem Schleifenschritt ein Speicherplatz zum Ablegen des Variableninhalts x auf dem Heap belegt und beim Beispiel B nicht (weil x ja wiederverwendet werden würde/könnte)?

Natürlich ist mir klar, dass so etwas unter Mico-Optimierung fällt, aber ich frage mich das schon länger und würde es gerne rein aus Interesse mal wissen
wie C# hier intern arbeitet.

Ich hoffe meine Frage war nicht allzu "dumm".

Danke für alle Antworten im voraus.

15.02.2013 - 00:25 Uhr

Danke für eure Antworten.

Nach langer Suche bin ich jetzt wohl auf die Lösung gestossen, nachdem ich das Projekt mal auf einem frischen System mit VS 2012 hab laufen lassen:

Dort wurde eine Exception geworfen und der Debugger von VS2012 gestartet, auf dem System mit VS2010 kommt wirklich keine Exception sondern die Anwendung hängt sich einfach auf.

In den Assembly-Einstellungen waren unter "Firma" seltsame Sonderzeichen und vermutlich haben diese beim Speichern der Settings Probleme in dem Firmenordner verursacht. Jedenfalls besteht das Problem nicht mehr seitdem ich dort eine "normale" Zeichenfolge eingetragen habe.

07.02.2013 - 00:49 Uhr

Kann es sein, dass bei Dir der Windows-Prozess "Anwendungserfahrung" deaktiviert/beendet ist?

06.02.2013 - 23:24 Uhr

Hi,

ich habe hier eine VB.Net-Anwendung (Framework 4.0) die nicht auf Winforms und nicht auf WPF basiert sondern einen komplett eigenen Gui-Renderer auf Basis der Direct2D-API verwendet.

Dazu wurde das Projekt ursprünglich als leeres VB.Net-Projekt angelegt.

Diese Anwendung verwendet die My.Settings um diverse Benutzereinstellungen zu speichern und genau dies führt zu meinem Problem.

Sobald das Executable außerhalb des Visual-Studio 2010 Debuggers gestartet wird führt jeder Zugriffsversuch auf My.Settings sofort zum Absturz des Programms.

Nun habe ich einfach mal alles drumherum aussen vorgelassen und ein leeres VB.Net Projekt erstellt, eine Anwendungskonfiguration im Designer von VS 2010 erstellt und einen Zugriff auf My.Settings in einem Try/Catch-Block versucht.

Auch in diesem simplen Szenario tritt der oben beschriebene Fehler auf: starte ich das Projekt im Debugger über VS sind die Settings wie gewohnt ansprechbar, starte ich die .exe kommt es zum Programmabsturz. Eine Exception wird dabei seltsamerweise nicht mal geworfen, dies habe ich ausgiebig getestet.

Ebenso habe ich bei diesem Problem keine Möglichkeit vorher zu prüfen ob irgendetwas 'Nothing' ist, denn wirklich jeder Zugriff auf 'My.Settings' führt sofort zum Absturz des Programms, außerhalb des VS-Debuggers.

Ich vermute das dies nicht mal VB-spezifisch ist, sondern möglicherweise in C# genau so, darum frage ich mal in diesem Forum nach ob jemand eine Idee hat woran das liegen könnte?

Vielen Dank für alle Antworten im voraus,
Astrix

17.01.2013 - 01:46 Uhr

Hi Klausi,

grundsätzlich sollte Deine Namensgebung natürlich kein generelles Problem darstellen.

Jedoch sollten, meines Wissens nach, lt. Microsoft-Konvention die Tabellen stets im Plural gehalten sein und die Entity-Objekte den Singular wiedergeben, anders kenne ich dies auch nicht von meiner beruflichen Praxis.

Beispiel: Entity-Objekt "User" FROM Tabelle "Users".

Und Abkürzungen die nur Du kennst sollten vermieden werden, besser ist immer man schreibt es aus (hiermit meine ich Dein "_RL", ich wüsste nun nicht was denn "_RL" bedeuten sollte), denke immer daran bei Namensgebungen an Betriebsfremde Entwickler zu denken, die sich (warum auch immer) schnell in fremden Code zurechtfinden müssen.

Viele Grüße
Astrix

17.01.2013 - 01:29 Uhr

Hallo zusammen,

ich würde gerne in meiner WPF-Applikation (.NET Framework 4.0), die dem MVVM-Muster folgt, Plugins einbinden.

Diese Plugins sind dabei WPF-Steuerelemente, die vom Benutzer des Programms beliebig geladen und auf einem Canvas meines Hauptprogramms angeordnet werden können.

Jedes Plugin, welches ich dynamisch in mein Hauptprogramm laden möchte, hat somit ebenfalls eine View, ein ViewModel und ein Model.

Mein Hauptprogramm muss nun diese Plugins verwalten und ich weiß nun nicht wie ich dies nun MVVM-konform umsetzen kann.

Denn ich habe dabei folgende Situation: der Canvas meines Hauptprogramms (der alle Views der geladenen Plugins anzeigt) muss ja die Views der Plugins kennen und entsprechend anordnen und darstellen, ebenso muss das Model aber die Berechnungslogiken der geladenen Plugins kennen und die Models der Plugins ebenfalls ansprechen können.

Konkret sähe dies so aus, dass die View meines Hauptprogramms eine Liste der Views der geladenen Plugins halten müsste, dass Model meines Hauptprogramms eine Liste der dazugehörigen Plugin-Models.

Mein erster Denkansatz war nun für jedes dieser Plugins eine Basisklasse zu erstellen, die über Properties bekannt gibt welche Instanz der View, des dazugehörigen ViewModels und des Models so ein Plugin beeinhaltet, aber dann hätte ich ja quasi keine lose Kopplung der Schichten mehr, oder?

Wie setzt man denn sowas in MVVM um?

Grüße
Astrix

16.12.2012 - 03:41 Uhr

Hallo zusammen,

ich habe mir für eine WPF-Anwendung unter dem .NET Framework 4.0 eine Klasse erstellt die von Canvas erbt.

Ich möchte auf einem Canvas eine (in gewissem Maße unbestimmte) Anzahl vom Anwender frei definierbarer "Plugins" darstellen können (jedes Plugin wiederum ist einfach ein WPF-Control welches von FrameworkElement ableitet).

Dabei stellt meine Canvas-Klasse eine gewisse Form von grafischer Virtualisierung bereit, denn es werden nur die Children-Elemente bei einem Mouse-Panning-Ereignis auf dem Canvas dargestellt die sich auch wirklich im sichtbaren Bereich befinden.

So klappt das eigentlich auch super, auf meinem Laptop funktioniert es mit weit über 250.000 Elementen immer noch recht flüssig (soviele habe ich in der Anwendung selbstverständlich nicht, da sind es eher so im "Worst-Case" 200 Elemente).

Mit einem gehaltenen Mausklick auf dem Canvas und Ziehen der Maus kann ich jetzt durch den gesamten "virtuellen" Canvas navigieren ("Panning").

Doch bewege ich die Maus dabei recht schnell kommt es zu seltsamen Artefakten in der Grafikdarstellung (und seltsamerweise in sämtlichen anderen Controls die ich in meiner Main-View definiere!).

Dazu habe ich hier einmal einen Screenshot angehängt. Bewege ich die Maus relativ langsam treten diese Bildfehler jedoch überhaupt nicht auf, es passiert erst wenn ich die Maus recht schnell hin- und herschiebe). Darum vermute ich, dass ich irgendwo in meiner Klasse einen Denkfehler habe, doch finde ich diesen einfach nicht.

Vielleicht hat ja jemand von euch einen Tipp was ich hier falsch mache?

PS: der Code ist in VisualBasic.Net programmiert und leider nicht in C# übersetzt, darum hoffe ich, dass dies auch okay ist für euch.

Imports MeinProjekt.Plugins
Imports MeinProjekt.ViewModels

Imports System.Windows.Input

Namespace Views.Controls

    ''' <summary>
    ''' Stellt Methoden für einen vereinfachten virtualisierten Canvas bereit.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class Desktop
        Inherits Canvas

        ''' <summary>
        ''' Liste der Plugins (ToDo: Dependency-Property).
        ''' </summary>
        ''' <remarks></remarks>
        Private ReadOnly _Plugins As New List(Of Plugin)

        ''' <summary>
        ''' Panning-Offset X für das Scrolling durch den Desktop.
        ''' </summary>
        ''' <remarks></remarks>
        Private _ViewPortOffsetX As Double = 0

        ''' <summary>
        ''' Panning-Offset Y für das Scrolling durch den Desktop.
        ''' </summary>
        ''' <remarks></remarks>
        Private _ViewPortOffsetY As Double = 0

        ''' <summary>
        ''' Gibt zurück ob der Panning-Modus aktiv ist oder legt dies fest.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Property IsPanning As Boolean
            Get
                Return _IsPanning
            End Get
            Set(value As Boolean)
                If value Then
                    Cursor = Cursors.SizeAll
                Else
                    Cursor = Cursors.Arrow
                End If
                _IsPanning = value
            End Set
        End Property
        Private _IsPanning As Boolean = False

        ''' <summary>
        ''' Enthält die letzte Mausposition beim Panning.
        ''' </summary>
        ''' <remarks></remarks>
        Private _MousePosOnPanningStart As New Point(0, 0)

        Protected Overrides Sub OnMouseDown(e As MouseButtonEventArgs)
            MyBase.OnMouseDown(e)
            If e IsNot Nothing Then
                If e.LeftButton = MouseButtonState.Pressed Then
                    If Not _IsPanning Then
                        Mouse.Capture(Me)
                    End If
                    _MousePosOnPanningStart = e.GetPosition(Me)
                End If
                IsPanning = True
            End If
        End Sub

        Protected Overrides Sub OnMouseUp(e As MouseButtonEventArgs)
            MyBase.OnMouseUp(e)
            If e IsNot Nothing Then
                If e.LeftButton = MouseButtonState.Released Then
                    If _IsPanning Then
                        ReleaseMouseCapture()
                    End If
                    Cursor = Cursors.Arrow
                    IsPanning = False
                End If
            End If
        End Sub

        Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
            MyBase.OnMouseMove(e)
            If e IsNot Nothing Then
                If _IsPanning Then
                    Dim pos As Point = e.GetPosition(Me)
                    _ViewPortOffsetX += (_MousePosOnPanningStart.X - pos.X)
                    ValueLimiter.Limit(_ViewPortOffsetX, Double.MinValue, Double.MaxValue)
                    _ViewPortOffsetY += (_MousePosOnPanningStart.Y - pos.Y)
                    ValueLimiter.Limit(_ViewPortOffsetY, Double.MinValue, Double.MaxValue)
                    _MousePosOnPanningStart = e.GetPosition(Me)
                    AddViewPortChildren()
                End If
            End If
        End Sub

        Protected Overrides Sub OnRenderSizeChanged(sizeInfo As System.Windows.SizeChangedInfo)
            MyBase.OnRenderSizeChanged(sizeInfo)
            AddViewPortChildren()
        End Sub

        Private Sub AddViewPortChildren()
            Children.Clear()
            ' Nur die Plugins im Canvas darstellen die sich im sichtbaren Bereich befinden.
            ' ToDo: Abfragen zusammenfassen, hier nur zum testen separiert.
            For Each p As Plugin In _Plugins
                If p.Top + p.Height >= _ViewPortOffsetY Then
                    If p.Top <= _ViewPortOffsetY + RenderSize.Height Then
                        If p.Left + p.Width >= _ViewPortOffsetX Then
                            If p.Left <= _ViewPortOffsetX + RenderSize.Width Then
                                Children.Add(p)
                                SetLeft(p, p.Left - _ViewPortOffsetX)
                                SetTop(p, p.Top - _ViewPortOffsetY)
                            End If
                        End If
                    End If
                End If
            Next
        End Sub

        Public Sub New()
            Background = CType(FindResource("DesktopLightningY"), Brush)
            ' Mangels Dependency-Properties werden hier einfach zum Testen der Klasse 1000 Testplugins erstellt.
            For i As Integer = 0 To 999
                Dim p As New Plugin
                p.Width = 200
                p.Height = 150
                p.Left = 0 + i * 255
                p.Top = 0 + i * 55
                _Plugins.Add(p)
            Next i
            AddViewPortChildren()
        End Sub

    End Class

End Namespace

Im Screenshot stellt jedes blaue Rechteck ein Element von "Plugin" dar. Die rot-umrandeten Regionen zeigen die Bildfehler wenn ich die Maus beim "Panning" sehr schnell bewege.

Vielen lieben Dank für alle Antworten im voraus. Wenn ich mehr Infos bereitstellen soll sagt mir bitte bescheid.

Viele Grüße
Astrix

21.11.2012 - 15:40 Uhr

Danke für eure prompten Antworten 😃

Hi,
Das Entity Framework ist ein sehr unperformanter ORM - besonders wenns um Inserts geht. Das merkt man nicht, wenn man nur 2-3 Inserts pro Sekunde...
[...]
der MongoDB, die durschnittlich 200-fach schneller ist als das EF - bei bestimmten Konstellationen sogar weit über das 10.000-fache.

Das habe ich auch schon bemerkt, dazu habe ich (wenn auch nur mal rudimentäre) Benchmarks zwischen EF und herkömmlichen ADO.NET angestellt, da lagen EF und LINQ immer recht weit hinten. Aber ich persönlich mag das EF mittlerweile und ich glaube auch wenn uns als Programmierern Millisekunden schon viel erscheinen merkt das der Endbenutzer im Callcenter nicht wirklich. Darum ist es schon eine gute Sache Entwicklungszeit zu sparen, finde ich jedenfalls im Vergleich zu dem reinen Performance-Verlust.

Die MongoDB finde ich persönlich stark! Aber: solche Flat-basierten Datenbanken können wir beruflich leider net durchsetzen (da sind ganz andere "Entscheider" quasi "oben drüber".

Viele Grüße
Astrix

EDIT: @Abt: danke für Deine Performance-Analyse, dass sieht sehr interessant aus.

21.11.2012 - 15:11 Uhr

Hallo zusammen,

wir arbeiten beruflich mit dem Microsoft SQL-Server 2008 und dem Entity-Framework mit LINQ unter dem .NET-Framework 4.0.

Nehmen wir bitte einmal das folgende Szenario als Beispiel für meine Fragestellung an:

Ich habe eine Kundenstammdatentabelle "Customers" und jeder Kunde muss sich, nachdem er seine Stammdaten über ein Frontend erfasst hat, über einen Link, dem ihm per Mail zugesendet wird, seinen Kundenaccount zunächst aktivieren, wie das eben häufig so ist.

So habe ich in meiner Kundenstammdatentabelle beispielsweise ein Feld "Activated" vom Typ "datetime" und in diesem Feld sei "NULL" als Wert erlaubt.

Sobald der Kunde den Link in seiner E-Mail anklickt wird in der Datenbank das Feld "Activated" vom ursprünglichen Standardwert NULL auf das aktuelle Datum + Uhrzeit gesetzt.

Somit weiß ich (als Programmierer bzw. als mein Programm), zu jeder Zeit dass dieses Kundenkonto tatsächlich (zu dem angegeben Zeitpunkt) aktiviert wurde indem ich einfach dieses Feld "Activated" auf NOT NULL prüfe.

Mein Chef besteht jedoch darauf, dass diese Datumsfelder für solche Prüfungen nicht herangezogen werden sollen, sondern es muss immer zusätzlich ein Feld mit dem Präfix "Is" existieren. In diesem Beispiel gäbe es also noch ein Feld "IsActivated" vom Typ "tinyint" (warum eigentlich nicht vom Typ "bit"?) welches dann einfach 0 oder 1 je nach Aktivierungsgrad enthält da dies performanter abzufragen sei als auf NULL.

Aber stimmt das wirklich? Mich würde sehr interessieren wie andere Entwickler sowas umsetzen.

Das mit dem "Activated" war natürlich nur eins von vielen Beispielen. Jede Tabelle von uns hat auch noch "Deleted" und "IsDeleted" usw., so dass sowas echt häufig vorkommt.

Zudem würde mich interessieren warum - wenn denn das wirklich performanter sein sollte - ein tinyint 0/1 für den Server weniger belastend sein sollte als ein reines Bit-Feld (laut Microsoft SQL-Server Doku ist ja der Server sogar in der Lage mehrere einzelne Bit-Felder in einer Tabelle zusammenzufassen um nicht jedesmal ein Byte zu verschwenden?).

Viele Grüße und herzlichen Dank im voraus für alle Meinungen und Antworten,
Astrix