2013-05-20 3 views
1

모두 바인딩 된 전체 모델, 값이 컨트롤에 표시되지만 버튼 클릭 작업을 수행 할 수 없습니다 ... 제안 사항이 있습니까? 나는 무엇을 놓치고 잘못 했는가? 감사합니다보기에 바인딩 된 모델을 클릭하지만 작업을 클릭하십시오.

<Window x:Class="test" Title="test" Height="350" Width="525"> 
    <StackPanel Name="abc" Orientation="Vertical" DataContext="{Binding Path=EMP, Mode=TwoWay}" Margin="4" Height="153"> 
     <Label Content="Last Name:" Margin="0,0,4,0"/> 
     <TextBox Width="250" Text="{Binding Path=LastName}" Height="20"/> 
     <Button Grid.Row="2" Margin="0,0,4,0" Height="40" Width="40" 
       Command="{Binding Path=SaveCommand}" /> 
    </StackPanel> 
</Window> 

class EmployeeVM: ViewModelBase 
{ 
    private bool _Execute = true; 
    public EmployeeVM() 
    { 
     emp = new Model.Employee { FirstName = "abc", LastName = "xyz" }; 
    } 
    private string sFirstName; 
    private string sLastName; 
    private Model.Employee emp; 

    public Model.Employee EMP 
    { 
     get{return emp;} 
     set{emp = value; 
      OnPropertyChanged("EMP");} 
    } 
    public string LastName 
    { 
     get { return sLastName; } 
     set 
     { 
      sLastName = value; 
      OnPropertyChanged("LastName"); 
     } 
    } 

    #region Commands 
    private ICommand _SaveCommand; 
    public ICommand SaveCommand 
    { 
     get 
     { 
      return _SaveCommand = new CommandHandler(Save, _Execute); 
     } 
    } 
    #endregion 

    private void Save(object param) 
    { 
     ObservableCollection<Model.Employee> newIM = new ObservableCollection<Model.Employee>(); 
     foreach(Model.Employee e in newIM) 
     { 
      string a = e.FirstName; 
      string b = e.LastName; 
     } 
    } 
} 


public class CommandHandler : ICommand 
{ 
    Action<object> _act; 
    bool _canExecute; 

    public CommandHandler(Action<object> act, bool canExecute) 
    { 
     _act = act; 
     _canExecute = canExecute; 
    } 

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

    public event EventHandler CanExecuteChanged; 

    public void Execute(object parameter) 
    { 
     _act(parameter); 
    } 
} 
+0

정확히 달성하려는 내용을 상세하게 기재 해주십시오. –

+0

@MareInfinitus, CommandParameter에 여러 매개 변수를 전달하려고합니다. 해당 매개 변수를 수집 할 수 없으며 컬렉션을 지원하지 않습니다 ... 위의 경우 .. 1/i의 경우에 ... 확인 ... 하지만 ICommand의 Execute 메소드에 i/p 매개 변수를 하나 이상 전달하려면 ... 막혔습니다 ... 미리 감사드립니다. – Amit

+1

'i/p' 란 무엇입니까? 이 약어는 잘 알려져 있지 않습니다. "텍스트 말하기"를 이해할 수없는 우리를 돕기 위해 모든 단어를 철자하고 괄호 안에 약어를 기입하는 것이 가장 좋습니다. – user7116

답변

0

당신은 당신의 명령을 직접 쓸 수 있습니다.

다음은 내 명령에 사용하는 기본 클래스입니다.

인생을 더 편하게 해주는 아주 기본적인 것들이 있습니다.

  • Execute 방법은 객체를 받아, 그래서 당신은 당신이 당신의 명령에 작동합니다 사람 (이 대부분의 시간이다하는 ViewModel을 쉽게 전달 될 수
  • 배열을 통과 할 수있을 것입니다 이 경우 필요없는 경우 스 와이프합니다.)
  • 변경된 처리기가 CommandManager를 사용합니다. 이것은 매우 도움이됩니다.

아마도 몇 가지를 변경하고 싶을 것입니다. 제가 추가 한 것은 매우 도움이되기 때문입니다. (당신을 감안할 때

public class ExampleViewModel : PropertyChangedBase 
{ 
    public ExampleViewModel() 
    { 
     this.DoThisAndThatCommand = new ExampleCommand(this); 
    } 

    public CommandBase DoThisAndThatCommand { get; set; } 
} 


// and in XAML, you can use it like 
<Button x:Name="Ok" 
      Command="{Binding DoThisAndThatCommand }" /> 

: (특히 뷰 모델)

public abstract class CommandBase : ICommand 
{ 
    public abstract bool CanExecute(object o); 
    public abstract void Execute(object o); 

    public PropertyChangedBase ViewModel { get; set; } 

    public event EventHandler CanExecuteChanged 
    { 
     add { CommandManager.RequerySuggested += value; } 
     remove { CommandManager.RequerySuggested -= value; } 
    } 
} 

당신은 당신의 ViewModel에

public class ExampleCommand : CommandBase 
{ 
    public ExampleCommand (PropertyChangedBase viewModel) 
    { 
     this.ViewModel = viewModel; 
    } 

    public override void Execute(object o) 
    { 
     // something like 
     var settings = UnityContainer.Resolve<ISettings>(); 
     settings.MagicValue = (this.ViewModel as ConcreteViewModel).MagicValue; 
    } 

    public override bool CanExecute(object o) 
    { 
     return true; 
    } 
} 

처럼 구현을 할 것이다, 당신은 특성을 갖는하여보기로 명령을 노출 의 DataContext을 설정하여 ViewModelView을 올바로 연결 했음

이제 버튼을 클릭 할 때마다 명령 실행 메서드가 호출됩니다.

Command에 ViewModel이 있으므로 쉽게 작업 할 수 있습니다.

명령 내에 또는 ViewModel 내부에 단추를 갖는 것은 매우 드뭅니다. MVVM에 대한 속임수는 ViewModel에서 View을 분리하고 ViewModel에서 UIElements을 가지지 않는 것입니다.

PropertyChangedBase (이 중 하나는 Caliburn.Micro와 함께 제공)가없는 경우 간단한 INotifyPropertyChanged 구현을 사용하는 것이 좋습니다.

I found this one here, should be german though

공공 추상 클래스 NotifyPropertyChangedBase는 : { # 지역 <에서 INotifyPropertyChanged> 회원

/// <summary> 
    /// Is connected to a method which handle changes to a property (located in the WPF Data Binding Engine) 
    /// </summary> 

    public event PropertyChangedEventHandler PropertyChanged; 

    /// <summary> 
    /// Raise the [PropertyChanged] event 
    /// </summary> 
    /// <param name="propertyName">The name of the property</param> 

    protected void OnPropertyChanged(string propertyName) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 


    #endregion 

    private Dictionary<string, object> propertyValueStorage; 


    #region Constructor 

    public NotifyPropertyChangedBase() 
    { 
     this.propertyValueStorage = new Dictionary<string, object>(); 
    } 


    #endregion 



    /// <summary> 
    /// Set the value of the property and raise the [PropertyChanged] event 
    /// (only if the saved value and the new value are not equal) 
    /// </summary> 

    /// <typeparam name="T">The property type</typeparam> 
    /// <param name="property">The property as a lambda expression</param> 
    /// <param name="value">The new value of the property</param> 

    protected void SetValue<T>(Expression<Func<T>> property, T value) 
    { 
     LambdaExpression lambdaExpression = property as LambdaExpression; 

     if (lambdaExpression == null) 
     { 
      throw new ArgumentException("Invalid lambda expression", "Lambda expression return value can't be null"); 
     } 

     string propertyName = this.getPropertyName(lambdaExpression); 

     T storedValue = this.getValue<T>(propertyName); 

     if (!object.Equals(storedValue, value)) 
     { 
      this.propertyValueStorage[propertyName] = value; 

      this.OnPropertyChanged(propertyName); 
     } 
    } 


    /// <summary> Get the value of the property </summary> 
    /// <typeparam name="T">The property type</typeparam> 
    /// <param name="property">The property as a lambda expression</param> 
    /// <returns>The value of the given property (or the default value)</returns> 
    protected T GetValue<T>(Expression<Func<T>> property) 
    { 
     LambdaExpression lambdaExpression = property as LambdaExpression; 

     if (lambdaExpression == null) 
     { 
      throw new ArgumentException("Invalid lambda expression", "Lambda expression return value can't be null"); 
     } 

     string propertyName = this.getPropertyName(lambdaExpression); 
     return getValue<T>(propertyName); 
    } 

    /// <summary> 
    /// Try to get the value from the internal dictionary of the given property name 
    /// </summary> 
    /// <typeparam name="T">The property type</typeparam> 
    /// <param name="propertyName">The name of the property</param> 
    /// <returns>Retrieve the value from the internal dictionary</returns> 

    private T getValue<T>(string propertyName) 
    { 
     object value; 

     if (propertyValueStorage.TryGetValue(propertyName, out value)) 
     { 
      return (T)value; 
     } 
     else 
     { 
      return default(T); 
     } 
    } 


    /// <summary> 
    /// Extract the property name from a lambda expression 
    /// </summary> 
    /// <param name="lambdaExpression">The lambda expression with the property</param> 
    /// <returns>The extracted property name</returns> 
    private string getPropertyName(LambdaExpression lambdaExpression) 
    { 
     MemberExpression memberExpression; 

     if (lambdaExpression.Body is UnaryExpression) 
     { 
      var unaryExpression = lambdaExpression.Body as UnaryExpression; 
      memberExpression = unaryExpression.Operand as MemberExpression; 
     } 
     else 
     { 
      memberExpression = lambdaExpression.Body as MemberExpression; 
     } 

     return memberExpression.Member.Name; 
    } 
} 

아주 사용하기 쉬운을에서 INotifyPropertyChanged!

ViewModel에서 바인딩 에 대한 공용 속성 (매우 중요 함)을 제공하고 변경 알림을 시작해야합니다.

여기 INPC (에서 INotifyPropertyChanged)

public class LoginViewModel : NotifyPropertyChangedBase 
{ 
    public string UserName { get;set; } 
} 
이 INPC 구현이 당신을 위해 NotifyOfPropertyChange 호출을

의 기본 구현을 사용하는 방법의 예입니다, 당신은 걱정하지 않아도됩니다! 그러나 귀하의 사건에 가장 적합한 것을 조사해야합니다.

귀하의 질문에 이미 ViewModelBase가 있습니다. 아마 당신은 위의 것 대신이 것을 사용하기를 원할 것입니다.

+0

나는 당신의 요약을 웃어야 만했다 : D. .' – SeToY

+0

이 삭제했습니다;) 물론 생성되었지만 작성하지 않았습니다. –

+0

@MareInfinitus, 구현에 대해 자세히 설명해 주시겠습니까? 기본 클래스의 샘플을 의미합니까? 위의 코드에서 ICommand 속성을 버튼에 연결하지 못했습니다. 누락 된 항목이 있습니다. 따라서 버튼을 클릭 할 때 .cs 파일로 이동하지 않아도됩니다. – Amit

0

난 당신이 쓴 혼동했기 때문에, 영어로 작성하려고하십시오 (예, 등등 "B/C"및 "UC 이상이": P ..)

어쨌든, 같은 대한 문제는,이 그것을 수정해야합니다 :

<UserControl.Resources> 
     <C:MultiValueConverter x:Key="MultiParamConverter"></C:MultiValueConverter> 
    </UserControl.Resources> 

    <StackPanel Orientation="Vertical"> 
     <StackPanel Orientation="Horizontal"> 
      <Button Name="Expander" Content="+" Width="25" Margin="4,0,4,0" Command="{Binding ExpanderCommand}"> 
       <Button.CommandParameter> 
        <MultiBinding Converter="{StaticResource MultiParamConverter}"> 
         <Binding ElementName="Content"/> 
         <Binding ElementName="Expander"/> 
        </MultiBinding> 
       </Button.CommandParameter> 
      </Button> 
      <Label FontWeight="Bold">GENERAL INFORMATION</Label> 
     </StackPanel> 
     <StackPanel Name="Content" Orientation="Vertical" Visibility="Collapsed"> 
      <Label>Test</Label> 
     </StackPanel> 
    </StackPanel> 

명령 :

public ICommand ExpanderCommand 
     { 
      get 
      { 
       return new RelayCommand(delegate(object param) 
        { 
         var args = (object[])param; 
         var content = (UIElement)args[0]; 
         var button = (Button)args[1]; 
         content.Visibility = (content.Visibility == Visibility.Visible) ? Visibility.Collapsed : Visibility.Visible; 
         button.Content = (content.Visibility == Visibility.Visible) ? "-" : "+"; 
        }); 
      } 
     } 

및 컨버터 :

public class MultiValueConverter : IMultiValueConverter 
    { 
     public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      return values.ToArray(); 
     } 

     public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) 
     { 
      throw new NotImplementedException("No two way conversion, one way binding only."); 
     } 
    } 
0

먼저보기 모델 클래스는 DependencyObject이거나 INotifyPropertyChanged 인터페이스를 구현해야합니다. 적절한 MVVM 라이브러리를 항상 찾고 기본 뷰 모델 클래스를 사용할 수 있습니다.

CheckBox가 단추의 동일한 컨텍스트에 바인딩 할 수 있다고 XAML에서 판단합니다. 따라서 buttonGetDetailsClickCommand에 바인딩하는 동안 chkDuplicates을보기 모델 속성에 바인딩 할 수도 있습니다 (CheckDuplicates). 따라서이 속성은 뷰 모델 내부에 이미 있으므로 명령 매개 변수로 사용할 필요가 없습니다. 예 :

class TestViewModel : ViewModelBase 
{ 
    bool checkDuplicates; 
    public bool CheckDuplicates 
    { 
     get { return checkDuplicates; } 
     set 
     { 
      if(checkDuplicates != value) 
      { 
       checkDuplicates = value; 
       OnPropertyChanged("CheckDuplicates"); 
      } 
     } 
    } 

    //Everything else is same as before 
    // except the action 
    public void AnyAction(object param) 
    { 
     //no need for param anymore 
     //var parmValues = (Object)param; 
     bool test = this.CheckDuplicates; 
    }   
} 

뷰를 모델링해야하기 때문에 명령 바인딩의 매개 변수를 없애고 뷰 모델의 일부로 만들 수 있습니다.

+0

감사합니다 Zahir, MVVM에 초보자이므로 지금 당장 말한 내용에 대해 즉각적으로 반응 할 수 없습니다 ... 몇 가지 생각/코드 샘플 필요 ... 사용자가 몇 가지 설정을 할 때 UI 및 버튼에 2 개의 컨트롤이 있습니다. 가치 및 버튼을 클릭하십시오. 격자를 채울 필요가 있고 모든 MVVM을 통해 달성하고 싶습니다 .... 당신이 코드 또는 일부 코드에 링크를 도울 수 있다면 고마워요 ... 미리 감사드립니다. – Amit

+0

내가 말하고자하는 것은 체크 박스, 목록 상자 등의 UI 요소를 생각하는 대신 속성 및 변경 사항에 대해 생각할 필요가 있다는 것입니다. 우리는 단지 뷰 모델을 형성 할 필요가 있습니다. 그런 다음 UI 디자인은 묶음이됩니다. 기본 클래스의 경우 http://mvvmfoundation.codeplex.com/을 쉽게 사용할 수 있습니다. 몇 가지 추가 샘플 코드가 필요한 경우 "MVVM 라이브러리"또는 "ViewModelBase". – zahir

+0

감사합니다 Zahir 다시 한 번, 내가 몇 가지 변경 사항을 오늘 UI를, 가치 r에 제어 할 수 있지만, 버튼을 클릭하면 .cs 파일 (방법을 저장)에 가지 않을 컨트롤을 바인딩 할 수 있었다 : ( – Amit

관련 문제