myCSharp.de - DIE C# und .NET Community (https://www.mycsharp.de/wbb2/index.php)
- Entwicklung (https://www.mycsharp.de/wbb2/board.php?boardid=3)
-- GUI: WPF und XAML (https://www.mycsharp.de/wbb2/board.php?boardid=85)
--- Wie mit MVVM auf ComboBox SelectionChanged-Event reagieren? (https://www.mycsharp.de/wbb2/thread.php?threadid=122560)


Geschrieben von GeneVorph am 19.01.2020 um 19:13:
  Wie mit MVVM auf ComboBox SelectionChanged-Event reagieren?
Hallo,

ich glaube, es ist nur ein kleiner Denkfehler, der mich gerade vom Weiterkommen abhält, aber ich bekommes es alleine nicht hin.

Einer ObservableCollection vom Typ int soll immer das in einer ComboBox ausgewählte Element hinzugefügt werden.

Das Problem: die ComboBox befindet sich auf einem UserControl, das dynamisch hinzugefügt wird. Ich müsste also, nach allem was ich zu wissen glaube, im ViewModel des UserControls auf den SelectionChange reagieren. Da ich gerade versuche MVVM zu lernen, soll der CodeBehind unangetastet bleiben.

Die einzige Methode, die ich mir nun vorstellen kann, ist im XAML-Code auf das "SelectionChanged"-Event zu reagieren, mit Hilfe eines Event-Triggers. Sieht bei mir so aus:

XML-Code:
<UserControl x:Class="UserControlTest.PathControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"            <!-- stimmt das hier?--
>

             xmlns:local="clr-namespace:UserControlTest"
             mc:Ignorable="d"
             d:DesignHeight="60" d:DesignWidth="800">


    <StackPanel Orientation="Horizontal">

        <ComboBox x:Name="combo" Margin="10" MinWidth="60" VerticalAlignment="Center" ItemsSource="{Binding AvailableNumbers}" SelectedIndex="{Binding TheIndex}" SelectedItem="{Binding TheValue, Mode=TwoWay}">
            <d:Interaction.Triggers EventName="SelectionChanged">
                <d:InvokeCommandAction Command="{Binding SelectionChangedCommand}" CommandParameter="SelectedItem" />
            </d:Interaction.Triggers>
        </ComboBox>

        <TextBox Margin="10" MinWidth="120" Text="{Binding TheText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    </StackPanel>
</UserControl>

Das Command (SelectionChangedCommand) stelle ich im ViewModel des UserControls bereit. Wenn ich ein Item aus der ComboBox auswähle, kann ich im Debugger jedoch sehen, das dieses Command nie ausgeführt wird.
Ich vermute derzeit zwei Fehler: die Deklaration des Namespace für Interactions (s. Kommentar im XAML-Code), bzw. ein fehlender Schritt in der UserControl ViewModel-Klasse?

viele Grüße
Vorph


Geschrieben von Papst am 19.01.2020 um 22:12:
 
Der Namespace "d" ist meines Wissens immer vordefiniert, den solltest du nicht ändern. Generell hat dieser Einfluss auf den Designer (im Originalzustand).

Du suchst diesen hier:
 http://schemas.microsoft.com/expression/2010/interactivity

An sich sollte der Designer dir bereits sagen, dass im Namespace d kein Interaction enthalten ist.

Gefunden durch Google:  https://stackoverflow.com/questions/1048517/wpf-calling-commands-via-events


Geschrieben von GeneVorph am 19.01.2020 um 22:44:
 
Hallo Papst,

vielen Dank erstmal. Der von dir verlinkte Post auf StackOverflow war mein Ausgangspunkt; zwar motzt der Compiler nicht, wenn ich d: schreibe, aber du hast natürlich Recht.

Ich habe außerdem herausgefunden, dass man sich die Library für Interativity über NuGet-Konsole holen kann. Jedoch - ich bin derzeit etwas ratlos WAS ich genau in die Anweisung für die Event.Trigger schreiben muss

XML-Code:
<i:Interaction.Triggers>
    <i:EventTrigger>
        <!-- ??? -->
    </i:EventTrigger>
</i:Interaction.Triggers>

[Im code, den ich zuvor gepostet habe, wird noch eine Klasse InvokeCommandAction aufgerufen - die aber bei mir gar nicht existiert geschockt kann also auch nicht funktionieren.] --> EDIT: Blödsinn gelabert - bitte ignorieren!

Wie gesagt, Fehlermeldungen bekomme ich keine und das Ganze wird auch kompiliert.

Ich bin derzeit leider nicht an einem PC mit meinem Projekt; muss also leider bis morgen warten. Frage mich aber, wass ich nun anstelle der Fragezeichen ansprechen soll? Setter?

Gruß
Vorph


Geschrieben von KroaX am 19.01.2020 um 23:42:
 
Das magische Suchwort für dich lautet wohl EventToCommand. Unter diesem Begriff versteckt sich am häufigsten was du tun möchtest. Jedes gängige MVVM Framework hat dazu eine fertige Implementierung mitsamt der Einbindung der notwendigen Abhängigkeiten.

 https://stackoverflow.com/questions/5868589/mvvm-light-adding-eventtocommand-in-xaml-without-blend-easier-way-or-snippet

Das hier ist ein Beispiel mit MVVM Light. Eventuell ziehst du ja in Betracht ein bestehendes MVVM Framework zu nutzen anstatt selbst eines zu schreiben.


Geschrieben von MrSparkle am 20.01.2020 um 10:32:
 
Wenn der Benutzer einen Wert in der ComboBox auswählt, wird durch das Binding die Eigenschaft TheValue im ViewModel geändert. Wenn du dort im Setter auf die Änderung reagierst, brauchst du kein Event, kein Command und kein Package.


Geschrieben von GeneVorph am 20.01.2020 um 16:03:
 
Hallo,

vielen Dank für die Infos - ich hab's hinbekommen! Hier der Code, wie er hätte sein müssen, damit es funktioniert:

In der View des UserControls

XML-Code:
<UserControl x:Class="UserControlTest.PathControl"
             <!-- ...--
>

             <!--diesen Namespace einf├╝gen-->
             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
             <!-- ...-->

    <StackPanel Orientation="Horizontal">
        <ComboBox x:Name="combo" Margin="10" MinWidth="60" VerticalAlignment="Center" ItemsSource="{Binding AvailableNumbers}" SelectedIndex="{Binding TheIndex}" SelectedItem="{Binding TheValue, Mode=TwoWay}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding SelectionChangedCommand}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ComboBox>
        <TextBox Margin="10" MinWidth="120" Text="{Binding TheText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    </StackPanel>

    <!-- -->
</UserControl>

Im ViewModel des UserControls wird dann einfach das SelectionChangedCommand angemeldet - fertig. Danke für das Zauberwort, KroaX - tatsächlich fehlt mir manchmal das Vokabular verwundert

Aber:

Zitat:
Wenn der Benutzer einen Wert in der ComboBox auswählt, wird durch das Binding die Eigenschaft TheValue im ViewModel geändert. Wenn du dort im Setter auf die Änderung reagierst, brauchst du kein Event, kein Command und kein Package.

Ich frage mich ja, warum ich da nicht gleich draufgekommen bin! Ich überlege, ob das nicht sogar sauberer ist; denn tatsächlich brauche ich ja nur den geänderten Wert! Die View selbst interssiert sich in meinem Fall gar nicht mehr dafür, was mit dem Wert passiert; so vom Gefühl her würde ich sagen, dass man vlt. auf das SelectionChanged-Event nur dann mit einem EventToCommand reagieren sollte, wenn dadurch eine Relevanz für die View gegeben ist (veränderte Darstellungsoptionen, etc). Da ich hier aber aus dem Bauch raus argumentiere, kann und will ich dafür nicht die Hand ins Feuer legen. Es würde mich aber schon interessieren, wie sich das verhält, oder ob es schlicht Wurscht ist.

Nochmals Danke, macht's gut,
Vorph


Geschrieben von KroaX am 20.01.2020 um 16:17:
 
Zitat:
Ich frage mich ja, warum ich da nicht gleich draufgekommen bin! Ich überlege, ob das nicht sogar sauberer ist; denn tatsächlich brauche ich ja nur den geänderten Wert! Die View selbst interssiert sich in meinem Fall gar nicht mehr dafür, was mit dem Wert passiert; so vom Gefühl her würde ich sagen, dass man vlt. auf das SelectionChanged-Event nur dann mit einem EventToCommand reagieren sollte, wenn dadurch eine Relevanz für die View gegeben ist (veränderte Darstellungsoptionen, etc). Da ich hier aber aus dem Bauch raus argumentiere, kann und will ich dafür nicht die Hand ins Feuer legen. Es würde mich aber schon interessieren, wie sich das verhält, oder ob es schlicht Wurscht ist.

Nochmals Danke, macht's gut,
Vorph

Am saubersten ist das was am ehesten deinem Usecase entspricht. Wenn du eine Aktion nur auslösen möchtest wenn der Benutzer über die UI eine Änderung an der Combobox vollzieht wäre es möglicherweise sauberer es über ein EventToCommand zu lösen.

Bedenke nämlich: Eine Änderung am Property innerhalb deines ViewModels würde dieselbe Bedeutung haben wie die Benutzerinteraktion aus der UI. Und manchmal möchte man dazwischen unterscheiden können.


© Copyright 2003-2020 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 04.06.2020 20:20