2016-07-20 14 views
0

Ich versuche WPF/MVVM zu lernen, und aus pädagogischen Gründen erstelle ich eine einfache Anwendung. Ich habe einige Probleme bei der Implementierung eines Command Object.Implementieren Sie ein Befehlsobjekt, das eine Eigenschaft in meinem Viewmodel ändert

Wenn ein Button-Steuerelement angeklickt wird, möchte ich die Hintergrundfarbe des Grid ändern mit einem Command Object gelb. Es gibt eine Menge Dinge darüber, wie man das macht, aber ich möchte es auf die saubere Art machen. Im Allgemeinen möchte ich eine lose Kopplung zwischen View, ViewModel und der Command Object erreichen, um diese Klassen zu testen.

Auch ich möchte nicht einige Bibliotheken wie Prism verwenden, weil ich die MVVM zuerst vollständig verstehen muss.

Ich habe ein Codebeispiel, aber es hat natürlich keine Funktionalität. Stellte es einfach aus Bequemlichkeitsgründen vor.

Meine Ansicht XAML

<Window x:Class="Calendar.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:Calendar" 
    mc:Ignorable="d" 
    Title="MainWindow" Height="350" Width="480"> 

<Grid Background="{Binding BackgroundColour}" Margin="0,0,2,0"> 
    <Button Margin="197,247,200,-239" Grid.Row="3" Grid.ColumnSpan="2" Command="{Binding SubmitCommand}">Color</Button> 
</Grid> 

Meine Modelview Klasse

public class MainWindowViewModel : INotifyPropertyChanged { 

    //Command part 
    ICommand SubmitCommand; 
    public MainWindowViewModel(ICommand command) { 
     SubmitCommand = command; 
    } 

    //Data Binding part 
    public event PropertyChangedEventHandler PropertyChanged; 
    private Brush backgroundColour = (Brush)new BrushConverter().ConvertFromString("Red"); 
    public Brush BackgroundColour { 
     get { return this.backgroundColour; } 
     set { 
      if (value != this.backgroundColour) { 
       this.backgroundColour = value; 
       var handler = this.PropertyChanged; 
       if (handler != null) { 
        handler(this, new PropertyChangedEventArgs("BackgroundColour")); 
       } 
      } 
     } 

(es hat auch einen Bindungsteil Daten, aber es muss nicht mit meinem Problem zu tun)

Antwort

2

Sie möchten im Ansichtsmodell nichts mit Fenstern wie Farben (Pinsel oder Pinsel) zu tun haben. Verweise meinen untenstehenden Code.

<Window x:Class="MVVMNav_Learning.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:MVVMNav_Learning" 
    mc:Ignorable="d" 
    Title="Window1" Height="300" Width="300"> 
<Window.Resources> 
    <local:ColorConverterConverter x:Key="ColorConverterConverter"></local:ColorConverterConverter> 
</Window.Resources> 
<Grid> 
    <Grid Background="{Binding BackgroundColour,Converter={StaticResource ColorConverterConverter}}" Margin="0,0,2,0"> 
     <Button Margin="50" Command="{Binding SubmitCommand}">Color</Button> 
    </Grid> 
</Grid> 

public partial class Window1 : Window 
{ 
    public Window1() 
    { 
     InitializeComponent(); 
     this.DataContext = new ViewModel(); 
    } 
} 

public class ViewModel:INotifyPropertyChanged 
{ 
    private MyColor backColor; 

    public MyColor BackgroundColour 
    { 
     get { return backColor; } 
     set { backColor = value; OnPropertyChanged("BackgroundColour"); } 
    } 

    public ICommand SubmitCommand { get; set; } 

    public ViewModel() 
    { 
     BackgroundColour = MyColor.Red; 
     SubmitCommand = new BaseCommand(Execute); 
    } 

    public void Execute(object parameter) 
    { 
     BackgroundColour = MyColor.Yellow; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propName)); 
     } 
    } 
} 

public enum MyColor 
{ 
    Red, 
    Green, 
    Yellow 
} 

public class BaseCommand : ICommand 
{ 
    private Action<object> _method; 
    public event EventHandler CanExecuteChanged; 

    public BaseCommand(Action<object> method) 
    { 
     _method = method; 
    } 

    public bool CanExecute(object parameter) 
    { 
     return true; 
    } 

    public void Execute(object parameter) 
    { 
     _method.Invoke(parameter); 
    } 
} 

public class ColorConverterConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, 
     object parameter, CultureInfo culture) 
    { 
     MyColor color = (MyColor)value; 
     switch (color) 
     { 
      case MyColor.Red: 
       return Brushes.Red; 
      case MyColor.Green: 
       return Brushes.Green; 
      case MyColor.Yellow: 
       return Brushes.Yellow; 
      default: 
      { 
       return Brushes.Red; 
      } 
     } 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 
+0

Subeamanian Ihre bereitgestellten Code haben eine Menge Zeug, geben Sie mir etwas Zeit, um einen Blick, und ich werde mit Fragen zurückkommen. – dios231

+0

bei dieser Zeile 'SubmitCommand = new BaseCommand (Execute);' Wo ist es bei 'ViewModel' Konstruktor, wie das' ViewModel' über die 'Execute' Abhängigkeit weiß? – dios231

+0

Verweisen Sie auf die Basisbefehlsklasse. Dies ist eine übliche Implementierung von ICommand, bei der Sie keine separate Klasse zur Implementierung Ihrer Befehle verwenden müssen. Angenommen, in einer Seite, wenn Sie 5 Schaltfläche haben, müssen Sie nicht 5 Klassen erstellen, um die Klicklogik zu verarbeiten, und Sie können auch verhindern, dass Viewmodel-Informationen an die Befehlsklasse übergeben werden. BaseCommand wird eine Aktion haben, die eine Methode in Ihrem Viewmodel aufruft. Es ist eine glatte Art, Befehle zu handhaben. –

0

Sie sind nicht sehr klar, Ihre Frage, aber ich zocken es zu sein: Wie den Befehlsparameter für den Konstruktor des Viewmodels so zu konfigurieren, dass er die Hintergrundfarbe ändert?

Befehle tun ihre Arbeit, indem sie ICommand.Execute(Object) mit implementieren Also im Grunde Sie den Befehl Objekt, das Sie an den Konstruktor haben wollen, ein Verfahren zu haben, wie:

void Execute(object parameter) 
    { 
     viewModel.BackGroundColor=Brushes.Yellow; 
    } 

Dies ist umständlich: der Befehl von übergeben wird außerhalb des Viewmodels, aber es muss einen Verweis darauf haben, um die Hintergrundfarbe zu ändern. Vielleicht möchten Sie Ihr Design überdenken.

noch: für die Datenbindung Motor der SubmitChangedCommand sehen muss es eine Eigenschaft sein:

public ICommand SubmitChangesCommand {get;set;} 
+0

ok, lässt so stellen sich erneut die Frage mit einer anderen Form. Wie kann eine Schaltfläche die Hintergrundfarbe des Rasters ändern, wenn darauf geklickt wird? – dios231

+0

@ dios231 Wie kann eine Schaltfläche die Rasterhintergrundfarbe ändern, wenn sie mit einem Befehl * angeklickt wird? – Dabblernl

+0

ja, mit einem Befehl – dios231

0

Sie benötigen ein öffentliches Eigentum für die ICommand SubmitCommand zu erstellen und Sie können eine private DelegateCommand in seinem Getter verwenden/Setter.