2017-04-01 10 views
1

私は私のアプリにMVVMパターンをマスターするチュートリアルに従っています。UVMのMVVMパターンチュートリアルですが、コマンドをバインドするのはなぜですか?

私はチュートリアルをよく練習しましたが、私は命令の部分に行きました。ボタンにコマンドを適用しようとすると、全く動作しないように見えました。 私は他のMVVMソースを見てきましたが、このチュートリアルをインターネット上で見つけただけでなく、WPFのためのものですが、UWP Windows 10 Appsにも適用されています。

私はクラスとXamlビューを貼り付けます。

これは私のモデルである:

using System.ComponentModel; 

namespace MVVMDemo.Model 
{ 
public class Student : INotifyPropertyChanged 
{ 
    private string firstName; 
    private string lastName; 

    public string FirstName 
    { 
     get 
     { 
      return firstName; 
     } 

     set 
     { 
      if (firstName != value) 
      { 
       firstName = value; 
       RaisePropertyChanged("FirstName"); 
       RaisePropertyChanged("FullName"); 
      } 
     } 
    } 

    public string LastName 
    { 
     get { return lastName; } 

     set 
     { 
      if (lastName != value) 
      { 
       lastName = value; 
       RaisePropertyChanged("LastName"); 
       RaisePropertyChanged("FullName"); 
      } 
     } 
    } 

    public string FullName 
    { 
     get 
     { 
      return firstName + " " + lastName; 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged = delegate { }; 

    private void RaisePropertyChanged(string property) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property)); 
    } 
} 
} 

私はそれにエラーがないと考えているモデルコード。 これが私のViewModelです:

using MVVMDemo.Model; 
using System.Collections.ObjectModel; 

namespace MVVMDemo.ViewModel 
{ 
public class StudentViewModel 
{ 
    /*Let’s add a property of MyICommand type in StudentView Model class. 
    * Now we need to construct an instance in the StudentViewModel. We will 
    * use the overloaded constructor of MyICommand that takes two parameters.*/ 
    public MyICommand DeleteCommand { get; set; } 

    /*Now add the implementation of OnDelete and CanDelete methods.*/ 
    public StudentViewModel() 
    { 
     LoadStudents(); 
     DeleteCommand = new MyICommand(OnDelete, CanDelete); 
    } 

    private bool CanDelete() 
    { 
     //if (SelectedStudent != null) 
     // return true; 
     //return false; 
     return SelectedStudent != null; 
    } 

    private void OnDelete() 
    { 
     Students.Remove(SelectedStudent); 
    } 

    /*We also need to add a new SelectedStudent so that the user 
    * can delete the Selected Item from ListBox.*/ 
    private Student _selectedStudent; 

    public Student SelectedStudent 
    { 
     get 
     { 
      return _selectedStudent; 
     } 
     set 
     { 
      _selectedStudent = value; 
      DeleteCommand.RaiseCanExecuteChanged(); 
     } 
    } 
    public ObservableCollection<Student> Students 
    { 
     get; 
     set; 
    } 


    public void LoadStudents() 
    { 
     ObservableCollection<Student> students = new ObservableCollection<Student>(); 

     students.Add(new Student { FirstName = "Mark", LastName = "Allain" }); 
     students.Add(new Student { FirstName = "Allen", LastName = "Brown" }); 
     students.Add(new Student { FirstName = "Linda", LastName = "Hamerski" }); 

     Students = students; 
    } 
} 
} 

これは私のViewModelLocatorです:

using MVVMDemo.ViewModel; 

namespace MVVMDemo.VML 
{ 
public class ViewModelLocator 
{ 
private static StudentViewModel studentViewModel = new StudentViewModel(); 

    public static StudentViewModel StudentViewModel 
    { 
     get { return studentViewModel; } 
    } 
} 
} 

と最後にこれは私が上viewmodellocatorを適用しています私のUserControl StudentView

<UserControl 
    x:Class="MVVMDemo.Views.StudentView" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:MVVMDemo.Views" 
    xmlns:vml="using:MVVMDemo.VML" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" 
    DataContext="{Binding Source={StaticResource mainViewModelLocator}, Path=StudentViewModel}" 
    d:DesignHeight="300" 
    d:DesignWidth="400"> 

<!--We will apply MVVM Using ItemTemplates--> 
<UserControl.Resources> 
    <DataTemplate x:Key = "studentsTemplate"> 

     <StackPanel Orientation = "Horizontal"> 
      <TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}" 
     Width = "100" Margin = "3 5 3 5"/> 

      <TextBox Text = "{Binding Path = LastName, Mode = TwoWay}" 
     Width = "100" Margin = "0 5 3 5"/> 

      <TextBlock Text = "{Binding Path = FullName, Mode = OneWay}" 
     Margin = "0 5 3 5"/> 
     </StackPanel> 

    </DataTemplate> 
</UserControl.Resources> 

<Grid> 
    <StackPanel Orientation="Horizontal"> 
     <!--In StudentView.xaml, we need to add SelectedItem property in a ListBox 
     which will bind to the SelectStudent property.--> 
     <ListView ItemsSource="{Binding Students}" 
        ItemTemplate="{StaticResource studentsTemplate}" 
        SelectedItem="{Binding SelectedStudent}"/> 

     <Button Content = "Delete" 
       Command="{Binding DeleteCommand}" 
       HorizontalAlignment = "Left" 
       VerticalAlignment = "Top" 
       Width = "75"/> 
    </StackPanel>   
</Grid> 
</UserControl> 

私のビューでありますアプリケーションレベルのapp.xamlファイル:

<Application.Resources> 
    <vml:ViewModelLocator x:Key="mainViewModelLocator"/> 
</Application.Resources> 

と私はこのようなメインページの私の見解を呼び出す:

誰かが私を助けることができる、私はVS2015とVS2017でこのコードを実行してきましたし、[削除]ボタンが有効れることは決してありません、それはまた、削除するdoesntのリストビューまたはリストボックスからの行を変更しようとしましたが、何も違うようです。

ここで使用されているように、私はrelaycommandパターンを使用せずにコマンド実行しています。 私はあなたの助けに感謝します。

ありがとうございました!

答えて

5

編集:

はあなたが{X:バインド}とイベントに直接メソッドをバインドすることができます知っています(これは答えが、それを行うための別の方法ではありません)ICommandを使用する必要はありません。このよう:)

+1

をはい、私がいることを知っていたが、×:例えば、我々はカントのようなバインドは、いくつかの制限がありますUpdateSourceTriggerを使用すると、ElementName、RelativeSource、およびSourceにバインドできません。 なぜ私はBinding sintaxに固執するのが好きなのですか? あなたが意図している動作は、動作と同じではなく、clickイベントです。むしろ、コードビハインドでイベントを使用してビューイングやスタイリングを行い、ビューモデルをデータバインディング、ナビゲーション、および検証に厳密に維持します。 –

1

あなたが財産を高めるためにセッターの行が欠落していると

public async void SendFeedback() 
    { 
     // Code 
    } 

簡単には通知

public Student SelectedStudent 
{ 
    get 
    { 
     return _selectedStudent; 
    } 
    set 
    { 
     _selectedStudent = value; 
     RaisePropertyChanged("SelectedStudent"); // your version of this notifier 
     DeleteCommand.RaiseCanExecuteChanged(); 
    } 
} 
を変更

XAML

 <Button Grid.Row="4" 
     x:Uid="Send" 
     VerticalAlignment="Top" 
     HorizontalAlignment="Left" 
     MinWidth="80" 
     Click="{x:Bind ViewModel.SendFeedback}"/> 

コードの後ろ

上記の問題を解決するのに十分です、しかし、それはさておき、あなたは、単にCanDeleteでプライベートバッキングフィールドを確認することができます。

return _selectedStudent != null; 
+0

ありがとうございました!あなたは答えが私の問題を解決するのに十分であった。 私にとって気になる唯一のことは、CanDeleteメソッドでプライベートバッキングフィールドをチェックしたときにのみ機能することです。 なぜそれは公共のプロパティSelectedStudentで動作しませんでしたか? うまくいけば、あなたはこの疑問に答えることができます。私がこのページで見つけた例は次のとおりです。https://www.tutorialspoint.com/mvvm/mvvm_view_viewmodel_communication.htm パブリックプロパティのみを使用しています。 –

+0

人は気にしないでください。今はPublic Propertyを使って作業していますが、VS2017の何らかのバグだったはずです。あなたの答えをありがとう、私は前にINotifyPropertyChangedを追加しましたが、DeleteCommand.RaiseCanExecuteChanged()の後に置きます。 私はそれを前に置いた後、正しく動作し始めました。助けてくれてありがとう!!!いい答え。 –

+0

はい、ViewModelは ':INotifyPropertyChanged'を実装しなければなりません –

関連する問題