Binding mit Parametern

  • WPF

Es gibt 27 Antworten in diesem Thema. Der letzte Beitrag () ist von Johannes.

    Johannes schrieb:

    irgendwie sprechen wir oft nicht dieselbe Sprache

    Ja, das ist richtig. Ich bin jemand der klare Ansagen braucht da man sonst immer aneinander vorbeireden wird. =O Denn...

    Johannes schrieb:

    So ist der normale Eingabemodus, ein Textfeld mit dem ich in die Datenbank schreibe.

    Das ist so ein Beispiel. Du schreibst beim suchen ja nicht in eine Datenbank. Du suchst Datensätze anhand eines Strings. Das ist ein signifikanter Unterschied. Schreiben/Lesen.

    OK. Ich mach dir mal ein rudimentäres Beispiel wie man sowas in der Art macht, obwohl ich es glaube ich noch immer nicht richtig verstehe.
    Sobald ich daheim bin bereite ich dir mal was vor.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo,
    ich fürchte, das ist eine andere Baustelle und evtl. ein anderes Thema, aber weil ich gerade mit der Combobox spiele.

    Die Performance ist schrecklich!

    Nur ein Experiment:
    Ich fülle im Konstruktor des Formulars eine CBList = New ObservableCollection(Of CBElement)
    und CBElement ist eine Klasse mit zwei String-Property Name, Key
    Die CBList wird also einmal mit ca. 7000 Datensätzen gefüllt, was in "Null Komma Nix" erledigt ist, jedenfalls kann ich beim Start der Anwendung keine nennenswerte Verzögerung feststellen.

    Die ComboBox.ItemSource binde ich auf CBList und in einem DataTemplate wird Text auf Name gebunden. Den Key kann ich mir dann von außen per SelectedItem in eine Textbox holen.

    Das hat alles funktioniert!

    Die Performance ist schrecklich, das Öffnen der ComboBox dauert jedesmal(!) 2 bis 3 Sekunden. (Ich hab mal gelern, ein UserInterface muss spätenstens nach 0,7Sekunden antworten, sonst hat der Anwender Stress.)

    Ich hatte schon die Idee, ohne eine ObservableCollection zu arbeiten und die Elemente direkt mit Items.Add in die ComboBox zu schreiben, hat aber nicht funktioniert und ob das dann schneller ist?
    Auch die Klasse CBElement zu vereinfachen und statt einer Property einfach zwei Public String Variablen zu benutzen hat nichts gebracht, bzw. dann funktioniert die Bindung nicht.

    In Access hatte ich mal das Problem, dass eine ComboBox mit einer wahnsinnig komplizierten Textvergleichs-Abfrage gefüllt werden musste. Diese Abfrage dauerte fast eine halbe Minute, weshalb ich die Daten erst bei Bedarf in die ComboBox laden ließ. Später war keine erneute Abfrage mehr nötig und ComboBox klappt ohne Verzögerung auf. Bei WPF ist die Verzögerung aber bei jedem einzelnen aufklappen der Liste.

    Anderes Thema:
    Aus Access (WindowsForms) kenne ich das Verhalten, dass ein Eintrag automatisch ausgewählt wird, wenn man im Textfeld etwas schreibt ("AutoComplete"), das funktioniert auch noch nicht.

    Entschuldige, kommst du neben der Beantwortung meiner Fragen noch zu deiner eigenen Arbeit?

    Vielen Dank!
    Und ich sehe gerade, dass du dich meines Problems mit dem SuchButton annehmen willst. Ziemlich Cool und ich freu mich drauf!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Johannes“ ()

    Hallo Johannes

    Ja, keine Angst, ich komm noch zum Arbeiten. Das ist nicht das Thema.

    Bez. deines letzten Posts (Bitte bleibe immer bei einem Thema und nur diesem, nur so behalten alle die Übersicht) mach bitte einen neuen Thread auf und versuche dein Problem so zu Beschreiben das man es nachvollziehen kann wobei ich in diesem Fall (das kann mehrere Ursachen haben) wohl besser ist und machst ein Beispiel mit Beispieldaten und stellst es Online. Aber du hast definitiv ein Designproblem wenn du in eine Combobox 7000 Datensätze laden willst. Auch mit AutoComplete ist das keine praktikable Lösung. Heute haben wir weit bessere Möglichkeiten sowas zu lösen. das ist nix in Sachen Usability. Aber gut, das ist deine Entscheidung, nicht meine. ;(
    Aber zurück zum Thema


    Ich habe eine Lösung erstellt wie man es unter WPF machen sollte(!) und dir folgendes erstellt:

    Zwei neue DependencyProperties im DBUserControl. IsSearchable As Boolean und SearchCommand As ICommand
    IsSearchable bestimmt ob der Button für die Suche eingeblendet werden soll. Als ob die Suche gestattet werden soll. (Ja, das ist in der WPF nicht Boolean sondern Visibility, aber dazu komme ich noch)
    SearchCommand definiert einen Command damit du den Luxus hast von außen dem Button einen Command mittels Binding mitgeben kannst. Sprich, was passieren soll wenn auf den Button gekickt wird.
    Denn ich nehme mal stark an das du je nachdem um welches Feld es sich handelt evtl. was anderes machen willst. So kannst du es von außen steuern. Sollte das nicht gewünscht sein dann das Binding einfach wegmachen und das Property wieder löschen.
    Weitere Infos über Command wiedermal in meinem Tutorialreihe im Kapitel 2.1.8.6.

    Im XAML ist das wie folgt gebungen:

    XML-Quellcode

    1. <Button Content="Search" Grid.Column="2" Margin="3" Command="{Binding SearchCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:DBUserControl}}}"
    2. Visibility="{Binding IsSearchable, Converter={StaticResource BooleanToVisibilityConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:DBUserControl}}}"
    3. />

    Und sieht dann wie folgt aus:


    Wie du im XAML siehst ist hier ein Converter im Binding eingebunden:
    Dieser ist als Resource definiert:

    XML-Quellcode

    1. <UserControl.Resources>
    2. <local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
    3. </UserControl.Resources>


    Ein Converter ist eine simple Klasse welche das Interface IValueConverter implementiert. Weitere Infos (wie soll es anders sein ;-)) im Kapitel 2.1.4.4.
    In diesem Fall ist es die Klasse BooleanToVisibilityConverter:

    VB.NET-Quellcode

    1. Public Class BooleanToVisibilityConverter
    2. Implements IValueConverter
    3. Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
    4. If value.GetType() IsNot GetType(Boolean) Then
    5. Return Visibility.Collapsed
    6. End If
    7. Dim val As Boolean = Boolean.Parse(value)
    8. If parameter IsNot Nothing Then
    9. If parameter.ToString().ToLower() = "reverse" Then
    10. Return IIf(val, Visibility.Collapsed, Visibility.Visible)
    11. Else
    12. Return IIf(val, Visibility.Visible, Visibility.Collapsed)
    13. End If
    14. Else
    15. Return IIf(val, Visibility.Visible, Visibility.Collapsed)
    16. End If
    17. End Function
    18. Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
    19. Throw New NotImplementedException()
    20. End Function
    21. End Class


    OK, ich habe dir etwas mehr Implementiert als notwendig. Warum? Dazu komme ich gleich.
    Im Grunde wird geprüft ob der Übergebene Wert überhaupt ein Boolean Wert ist und wenn ja wird für True ein Visibility zurückgegeben und für False ein Collapsed.
    Aber ich habe dir, weil du ja dann wenn ich das richtig verstanden habe die ComboBox entgegengesetzt des Suchbuttons einblenden willst schonmal die Möglichkeit geschaffen hier als Parameter (Bindingparameter) den String "reverse" mitzugeben um somit diesen Converter auch "umkehren" zu können. :rolleyes:

    Bleibt nur noch die Klasse RelayCommand über. Solltest du das Kapitel zu Commands ansehen solltest du gleich zhum nächsten Kapitel übergehen, da gehts dann nämlich um RelayCommands welche dir das leben einfach nur um vieles leichter machen.

    So, ich hoffe ich habe es gut erklärt, sonst melde dich. Um mach bitte für das andere Thema einen neuen Thread auf und dann sehe ich mir das gerne an.

    Grüße
    Sascha
    Dateien
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo Sascha,

    vielen Dank für deine Mühe!

    Dir ist sicher klar, dass das nicht genau mein Design war.
    Aber in deinem Beispiel habe ich viele Informationen, wohin die Reise noch alles hingehen könnte. Danke!

    Meine eigenen Versuche sahen zunächst ähnlich aus, natürlich ohne die Command-Klasse.
    Mit einem VisibilityConverter hatte ich schon zu tun, habe mich aber in meinem Experiment dazu entschieden, die WPF.Visibility zu verwenden um so auf einen Converter verzichten zu können. Wenn ich den Button als ToogleButton verwende und dann gleich auf die Eigenschaft "Gedrückt" verweisen will, dann brauche ich den Converter natürlich.

    In einem Versuch vor einigen Tagen hatte ich mir so eine "Flip-Flop-Anzeige" mit einem DocPanel zusammen gezimmert und hier konnte die Schaltfläche die beiden Steuerelemente abwechselnd anzeigen, mit Grid war mir das nicht gelungen, da das zweite Control (die ComboBox) zur Laufzeit nicht auf die volle Breite "gestretcht" wurde.


    XML-Quellcode

    1. d:DesignHeight="13.25" d:DesignWidth="180">
    2. <UserControl.Resources>
    3. <AlternationConverter x:Key="AlternationConverter"/>
    4. </UserControl.Resources>
    5. <DockPanel LastChildFill="True">
    6. <Label x:Name="lblLabel" MinWidth="30" VerticalAlignment="Center" VerticalContentAlignment="Center" DockPanel.Dock="Left" />
    7. <Button x:Name="button" DockPanel.Dock="Right"
    8. Height="{Binding ActualHeight, ElementName=tbTexbox}"
    9. Width="{Binding ActualHeight, ElementName=tbTexbox}">
    10. <Image Source="zoom.png"/>
    11. </Button>
    12. <TextBox x:Name="tbTexbox" DockPanel.Dock="Top" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalAlignment="Center" VerticalContentAlignment="Center"/>
    13. <ComboBox x:Name="cbComboBox" DockPanel.Dock="Bottom" Visibility="Collapsed" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalAlignment="Center" VerticalContentAlignment="Center"/>
    14. </DockPanel>


    Obwohl ich alles margins und ähnliches entfernt habe verrutscht mir der Button etwas nach unten.


    Findest du meinen Fehler (ohne Augenkrebs zu bekommen?

    Liebe Grüße
    Johannes

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Johannes“ ()

    Hallo nochmals

    Naja, ein Dockpanel ist eher nicht so gut gewählt als Container für die Controls da nur ein Child sind richtig Strecken kann (Wie du ja gemerkt hast). Hier wäre ein Grid meine Wahl.
    Ich weis nicht warum es bei dir nicht klappen wollte. Aber wenn ich deinen Code so sehe bin ich versucht dir zu Unterstellen das du noch immer mit dem Designer arbeitest, zwar bereinigst du aber dennoch.
    Nur eine vermutung :whistling:

    Du musst im Falle eines Grids garnicht so viel an der Stellschraube drehen. Ohne viel einzustellen klappt das.

    XML-Quellcode

    1. <UserControl.Resources>
    2. <local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
    3. <Style TargetType="Button">
    4. <Setter Property="Margin" Value="3"/>
    5. <Setter Property="Padding" Value="3"/>
    6. </Style>
    7. <Style TargetType="Label">
    8. <Setter Property="VerticalAlignment" Value="Center"/>
    9. <Setter Property="Margin" Value="3"/>
    10. </Style>
    11. </UserControl.Resources>
    12. <Grid>
    13. <Grid.ColumnDefinitions>
    14. <ColumnDefinition Width="Auto"/>
    15. <ColumnDefinition Width="*"/>
    16. <ColumnDefinition Width="Auto"/>
    17. </Grid.ColumnDefinitions>
    18. <Label x:Name="lblLabel" MinWidth="30" Content="Testlabel" />
    19. <Button x:Name="button" Grid.Column="2">
    20. ...
    21. </Button>
    22. <TextBox x:Name="tbTexbox" Grid.Column="1" Visibility="{Binding ShowCombobox, ConverterParameter=reverse, Converter={StaticResource BooleanToVisibilityConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:UserControl1}}}"/>
    23. <ComboBox x:Name="cbComboBox" Grid.Column="1" Visibility="{Binding ShowCombobox, Converter={StaticResource BooleanToVisibilityConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:UserControl1}}}" />
    24. </Grid>


    Das klappt so wunderbar. hier ein Screenshot:




    PS: Wir entfernen uns immer weiter vom Ausgangsthema. ab nun bitte ein neues Thema erstellen sonst muss ich es splitten oder löschen.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo Sascha,

    du hast recht, an der ursprünglichen Frage: Wie kann ich einem Binding einen Parameter übergeben? sind wir wohl gescheitert.

    Ich hatte das so gemeint: Text="{Binding Path=<Ein Parameter>}".
    Ich konnte so etwas im Quelltext lösen, aber das gefällt dir nicht - kann ich verstehen.

    Du hast mir hier anschaulich erklärt, dass es bessere Wege gibt. OK

    Nur wenn jemand auf dieses Thema stößt, dann wäre das die Kurzfassung. "Frage nicht gelöst." :(

    Andererseits hast du mir hier viele Anregungen zum weiterarbeiten gegeben.
    Falls du noch eine Antwort anfügen willst, sonst würde ich das Thema als "Erledigt" markieren.

    Vielen Dank noch einmal!
    Und danke für das überarbeitete Control!
    Johannes

    Johannes schrieb:

    sind wir wohl gescheitert

    Ne, die Frage wurde beantwortet. Gleich in meinem ersten Beitrag.

    Nofear23m schrieb:

    Ja, das ist möglich mit der Eigenschaft Parameter.


    Nofear23m schrieb:

    Man muss hier nur bedenken das die Eigenschaft Parameter kein Binding unterstützt, du kannst also einen String mit übergeben aber du kannst nicht auf etwas Binden.


    In deinem Fall ist dies aber aus genau diesem Grund NICHT möglich da Parameter nur ein String sein kann und nicht per binding übergeben werden kann weil es kein Dependency Property ist.

    Alles was danach kahm ist einfach eine Hilfestellung zu deinem konkreten Problem was ja auch in Ordnung ist.

    Liebe Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##