2016-07-19 4 views
0

ObservableCollection에 바인드 된 ItemsControl이있는 UserControl이 있습니다. 이 ItemsControl의 DataTemplate은 TextBox와 Button이 포함 된 Grid입니다.MVVM을 사용하여 WPF에 동적으로 추가 된 UIElements를 연결합니다.

<UserControl.Resources> 
    <entities:SeparatingCard x:Key="IdDataSource"/> 
</UserControl.Resources> 
<ItemsControl ItemsSource="{Binding Cards}"> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition/> 
        <ColumnDefinition/> 
       </Grid.ColumnDefinitions> 
       <Grid.RowDefinitions> 
        <RowDefinition/> 
       </Grid.RowDefinitions> 
       <TextBox Text="{Binding Id, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" GotFocus="TextBox_GotFocus" Grid.Row="0" Grid.Column="0"/> 
       <Button DataContext="{Binding Source={StaticResource IdDataSource}}" Command="{Binding Accept}" Grid.Row="0" Grid.Column="1">Accept</Button> 
      </Grid> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

모델 파일에서 :

public ObservableCollection<SeparatingCard> Cards { get; set; } 

카드 클래스 : 여기

는 일부 코드 (업데이트)입니다

class SeparatingCard : INotifyPropertyChanged 
{ 
    private string _id; 
    public string Id 
    { 
     get { return _id; } 
     set 
     { 
      _id = value; 
      OnPropertyChanged("Id"); 
     } 
    } 
    public ActionCommand Accept { get; } 
    public SeparatingCard() 
    { 
     Accept = new ActionCommand(AcceptCommandExecute); 
    } 
    private void AcceptCommandExecute(object obj) 
    { 
     MessageBox.Show(Id); 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

카드는 런타임에 추가되고 나는 동적으로 얻을 내 UserControl에있는 새로운 textbox-button 쌍. 이제 각 쌍마다 다음 작업을 수행해야합니다.
- 텍스트 상자의 텍스트가 올바른지 확인하고 적절한 단추를 사용/사용하지 않도록 설정할 수 있습니다.
- 버튼을 클릭하면 해당 텍스트 상자에서 텍스트를 가져 와서 처리합니다.

MVVM을 통해이 모든 작업을 수행하고 싶습니다.
으로 내가 SeparatingCard 클래스에 ICommand 논리를 이동하려고 제안했다

private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     var text = (((sender as Button).Parent as Grid).Children 
      .Cast<UIElement>() 
      .First(x => Grid.GetRow(x) == 0 && Grid.GetColumn(x) == 0) as TextBox).Text; 
     MessageBox.Show(text); 
    } 

업데이트 :하지만 난 단지 직접 UI에 대한 액세스 권한 만 두 번째 작업을 구현하는 솔루션에왔다. 이제는 항상 null을 반환하고 내 명령을 참조하는 클래스 SeparatingCard 클래스의 개체를 확인할 수 없습니다. 업데이트는 위의 코드에 있습니다.

+1

그래서 구체적으로 문제가 있습니까? 컬렉션의 뷰 모델은 텍스트의 ID 값과 함께 있어야합니다. 이 뷰 모델은 또한'Button.Command' 속성에 바인딩 할 수있는'ICommand'를 가질 것입니다. 동일한 뷰 모델은 "올바른 것"을 검사하고 그에 따라'ICommand '에 대한'CanExecute()'값을 변경할 수 있습니다. 이 중 어느 것도 UI 요소에 대한 액세스가 필요하지 않습니다. 그것은 모두 뷰 모델 안에 있습니다. 이 모든 것에 도움이 필요하면 도움이 필요한 것이 무엇인지에 대한 정확한 설명과 함께 시도한 것을 분명히 보여주는 좋은 [mcve]를 제공해주십시오. –

+0

이상하게도 elvis 연산자를 사용하고 있지만'nameof()'또는 더 나은 방법으로는 [CallerMemberName] (https://msdn.microsoft.com/en-us/library/system.runtime)을 사용하지 않는 것이 좋습니다. compilerservices.callermembernameattribute.aspx) 특성을 사용합니다. – Will

+0

개인적으로 나는'ICommand'를 사용하여 실행 코드를 ViewModel에 넣었으나 대신 실제로'Click' 메서드를 사용하고자한다면 버튼의'.DataContext'를 형 변환 할 수 있습니다 :'var data = ((Button) sender) .DataContext as SeparatingCard; ' – Rachel

답변

1

Button.Click 대신 Button.Command를 사용하십시오.이 명령은 SeparatingCard의 일부 명령에 바인딩 할 수 있습니다. http://www.codeproject.com/Tips/813345/Basic-MVVM-and-ICommand-Usage-Example

그런 다음, SeparatingCard의 ViewModel 당신이 Button.Command에 결합 할 수있는 ICommand의 객체를 포함합니다 :

이 튜토리얼에서 봐 주시기 바랍니다. 사용자가 버튼을 클릭하면 이벤트가 해당 SeparatingCard 객체의 명령으로 전달됩니다.

+0

mvvm을 처음 사용했지만 실제로 프로젝트에서 명령을 사용했습니다. 난 그냥 버튼에서 텍스트 상자와 함께 작동합니다 기능 명령을 바인딩 할 수 없어요. – SHKVal

+0

사용자가 버튼을 클릭하면 명령이 SeparatingCard 내부에서 기능을 트리거합니다. 여기서 TextBox에 묶여있는 Id 필드를 참조 할 수 있습니다. – OrMiz

+0

이 솔루션을 이용해 주셔서 감사합니다.하지만 이제는'Id' 속성은 항상 null입니다. 코드 업데이트를 확인하십시오. 나는 실수를 저질렀을지도 모른다. – SHKVal

관련 문제