Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
WPF, MVVM und CommandBindings
Hunv
myCSharp.de - Member

Avatar #avatar-3429.png


Dabei seit:
Beiträge: 195

Themenstarter:

WPF, MVVM und CommandBindings

beantworten | zitieren | melden

Hi,

ich möchte gerne ein Programm schreiben, welches MVVM-conform ist. Dazu gehört auch, soviel ich bisher verstanden habe, nicht die "klassischen" z.B. Button_Click-Events eines Controls zu benutzen, sondern dies über CommandBindings umzusetzen.
Dazu habe ich bisher folgendes gemacht:

XAML:
<RibbonWindow 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MvvmTest.GUI_v2.ViewModels"
        xmlns:cmds="clr-namespace:MvvmTest.GUI_v2.ViewModels.Commands"
        x:Class="MvvmTest.GUI.MainWindow"
        Title="MvvmTest"      
        Height="600"
        Width="800"
        WindowState="Normal"
        WindowStartupLocation="CenterScreen"    
        >
    <RibbonWindow.DataContext>
        <local:ViewModelMain />
    </RibbonWindow.DataContext>

    <RibbonWindow.CommandBindings>
	<!-- Geht nicht -->
        <CommandBinding Command="cmds:Login.CmdLogin" CanExecute="Login_CanExecute" Executed="Login_Executed" />
	<!-- Geht auch nicht -->
        <CommandBinding Command="cmds:Login.CmdLogin" CanExecute="cmds:Login.Login_CanExecute" Executed="cmds:Login.Login_Executed" />    
</RibbonWindow.CommandBindings>

    <Grid>
        <Button Content="Login" Command="cmds:Login.CmdLogin" HorizontalAlignment="Left" VerticalAlignment="Top" IsDefault="True" Width="200"  Margin="0,0,0,5"/>
    </Grid>
</RibbonWindow>

Mein ViewModelMain (NameSpace: MvvmTest.GUI.ViewModels) ist zur Zeit noch leer.
Für die Commands möchte ich gerne im NameSpace MvvmTest.GUI.ViewModels.Commands jeweils eine Klasse erstellen, in denen dann die gewünschten Aktionen durchgeführt werden sollen.

Eine so eine Klasse sieht z.B. so aus:


namespace MvvmTest.GUI_v2.ViewModels.Commands
{
    public class Login
    {
        public static RoutedUICommand CmdLogin = new RoutedUICommand("Login", "Login", typeof(Login));

        public void Login_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
            //e.Handled = true;
        }

        public void Login_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            Console.Beep();
        }
    }
}

Mein Problem ist nun:
wie bekomme ich dem CommandBinding Beigebracht, dass er aus der Klasse Login das CanExecute und Executed aufrufen soll und nicht aus der CodeBehind-Datei? Im XAML Code oben habe ich bereits zwei Möglichkeiten ausprobiert, welche mir logisch erschienen, aber beide nicht funktionieren.

Bei der ersten Variante gibt es den Fehler
Fehler
'MvvmTest.GUI.MainWindow' does not contain a definition for 'Login_Executed' and no extension method 'Login_Executed' accepting a first argument of type 'MvvmTest.GUI.MainWindow' could be found (are you missing a using directive or an assembly reference?)
Hier sucht er in der Code-Behind-Datei nach den Methoden.

Bei der zweiten Variante gibt es den Fehler:
Fehler
CanExecute="cmds:Login.Login_CanExecute" is not valid. 'cmds:Login.Login_CanExecute' is not a valid event handler method name. Only instance methods on the generated or code-behind class are valid.

Beides kompiliert nicht.

Des weiteren hatte ich auch schon versucht die Login-Klasse sowie die (Can)Execute-Methoden static zu machen, aber auch das hat in der Verzweiflung nichts am Fehler und den Meldungen geändert.

Ich bin ein wenig ratlos und finde auch über den Freund mit den 6 Buchstaben keine Lösung, die mir im Ansatz weiterhilft. In die CodeBehind-Datei möchte ich eigentlich nichts schreiben.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Hunv am .
Visit me @ www.beremote.net
private Nachricht | Beiträge des Benutzers
Coffeebean
myCSharp.de - Team

Avatar #avatar-3295.gif


Dabei seit:
Beiträge: 2461
Herkunft: Deutschland/Schweiz

beantworten | zitieren | melden

Hallo Hunv,

ein Command ist eine eigene Klasse. Somit mach eine Klasse. Leite diese von ICommand ab und du bekommst deine Methoden, die du auch schon kennst.


public class MyCommandImpl : ICommand, IMyCommand
{
	public bool CanExecute(object parameter)
	{
		return true;
	}

	public void Execute(object parameter)
	{
		//Do Something
	}

	public event EventHandler CanExecuteChanged;
}

Dann bietest du das einfach in deinem VM an:


public class MainViewModel
{
	public IMyCommand MyCommand { get; set; }

	public MainViewModel()
	{
		MyCommand = new MyCommandImpl();
	}
}

Wenn der Datacontext gesetzt ist, kannst dus einfach binden.
<Button Command="{Binding MyCommand}" Height="20"></Button>

Gruss

Coffeebean
private Nachricht | Beiträge des Benutzers
unconnected
myCSharp.de - Member

Avatar #avatar-3200.jpg


Dabei seit:
Beiträge: 862
Herkunft: Oerlinghausen/NRW

beantworten | zitieren | melden

Zitat
ein Command ist eine eigene Klasse

Ich für meinen Teil bin es leid für jeden Button Klick eine neue Klasse zu erstellen, zumal wenn es absehbar ist, das ich diesen Code genau an einer Stelle benötige. Mich hätte das damals fast wieder zum Code Behind gebracht. Bis ich dann über dutzende Implementierungen von RelayCommand oder DelegateCommand gestolpert bin. Das macht einem das Leben mit Wpf doch sehr viel angenehmer.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von unconnected am .
private Nachricht | Beiträge des Benutzers
t0ms3n
myCSharp.de - Member



Dabei seit:
Beiträge: 319

beantworten | zitieren | melden

Man sollte dies einfach entsprechend dem jeweiligen Anwendungsfall nutzen. Habe ich ein Command was immer wieder genutzt wird bietet es sich an dafür eine entsprechende Klasse zu erstellen.

Für (einfache) spezifische Fälle sehe ich dies wie unconnected.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von t0ms3n am .
private Nachricht | Beiträge des Benutzers
Hunv
myCSharp.de - Member

Avatar #avatar-3429.png


Dabei seit:
Beiträge: 195

Themenstarter:

beantworten | zitieren | melden

Hi Coffeebean,

vielen Dank für deine Antwort. Das hat mir sehr weitergeholfen!
Ob ich wirklich für jeden Click eine eigene Klasse mache oder ob ich das in der Praxis dann ggf. doch anders mache, wird sich zeigen. Erstmal aber möchte ich es mit eigenen Klassen machen um zu wissen wie es dann in der Theorie und Praxis mal alles funktionieren würde.
Visit me @ www.beremote.net
private Nachricht | Beiträge des Benutzers