2016-07-19 7 views
0

Ich habe UserControl mit ItemsControl gebunden an ObservableCollection. DataTemplate in diesem ItemsControl ist ein Raster mit TextBox und Button.Verbinden Sie UIElements dynamisch hinzugefügt in WPF mit MVVM

Hier einige Code (Aktualisiert):

<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> 

In Modelldatei:

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

Karte Klasse:

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)); 
    } 
} 

Karten werden in Laufzeit hinzugefügt und ich ein dynamisch erhalten neues Textbox-Tastenpaar in meinem UserControl. Jetzt in jedem Paar muss ich die folgenden Dinge tun:
- Überprüfen können, ob der Text im Textfeld korrekt ist und entsprechende Schaltfläche deaktivieren/aktivieren.
- Klicken Sie auf Schaltfläche, um den Text aus der entsprechenden Textbox zu erhalten und zu bearbeiten.

Ich möchte das alles über MVVM getan. Aber ich kam nur zu Lösung, die direkt Zugriff auf UI und implementiert nur die zweite Aufgabe:

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); 
    } 

aktualisiert
Wie vorgeschlagen wurde ich versuchte ICommand Logik SeparatingCard Klasse zu bewegen. Nun gibt es immer null zurück und ich kann nicht überprüfen, auf welches Objekt der Klasse SeparatingCard sich mein Befehl bezieht. Updates finden Sie im obigen Code.

+1

Also, was genau haben Sie Probleme mit? Sie sollten in Ihrer Sammlung ein Ansichtsmodell mit dem ID-Wert für den Text haben. Dieses Ansichtsmodell besitzt auch einen ICommand, den Sie an die Eigenschaft 'Button.Command' binden können. Dasselbe Ansichtsmodell kann prüfen, was "korrekt" ist und den "CanExecute()" - Wert für den "ICommand" entsprechend ändern. All dies erfordert keinen Zugriff auf UI-Elemente. Es ist alles innerhalb des Ansichtsmodells. Wenn Sie Hilfe bei all dem benötigen, stellen Sie bitte eine gute [mcve] zur Verfügung, die deutlich zeigt, was Sie versucht haben, mit einer genauen Erklärung, wofür Sie Hilfe benötigen. –

+0

Odd Sie verwenden den elvis-Operator, aber immer noch nicht den Vorteil von 'nameof()' oder, besser noch, den [CallerMemberName] (https://msdn.microsoft.com/en-us/library/system.runtime. compilerservices.callermembernameattribute.aspx) Attribut. – Will

+0

Persönlich würde ich zu einem 'ICommand' wechseln, so dass der Code zum Ausführen im ViewModel ist, aber wenn Sie wirklich eine' Click' Methode verwenden möchten, können Sie den '.DataContext' der Schaltfläche:' var data = ((Button) sender) .DataContext als Trennkarte; ' – Rachel

Antwort

1

Anstatt Button.Click zu verwenden, verwenden Sie Button.Command, das Sie an einen Befehl in SeparatingCard binden können.

Bitte schauen Sie in diesem Tutorial: http://www.codeproject.com/Tips/813345/Basic-MVVM-and-ICommand-Usage-Example

Dann SeparatingCard Ansichtsmodell wird ein ICommand Objekt enthalten, die Sie Button.Command binden können. Wenn der Benutzer also auf die Schaltfläche klickt, wird das Ereignis an den entsprechenden Befehl des SeparatingCard-Objekts weitergeleitet.

+0

Ich bin neu bei MVVM, aber ich habe tatsächlich Befehle in meinem Projekt verwendet. Ich verstehe nur nicht, wie ich den Befehl von Button zu Funktion binden kann, die mit seinem Textfeld funktioniert. – SHKVal

+0

Wenn der Benutzer auf die Schaltfläche klickt, löst der Befehl eine Funktion in SeparatingCard aus. Dort können Sie auf das Id-Feld verweisen, das an Ihre TextBox gebunden ist. – OrMiz

+0

Danke für diese Lösung, aber jetzt 'Id' Eigenschaft ist immer Null. Bitte überprüfen Sie die Code-Aktualisierungen. Vielleicht habe ich da ein paar Fehler gemacht. – SHKVal