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