如何在视图中编辑可观察集合中的项
在我的应用程序中,我正在显示一个可观察集合中的项,并希望用户能够编辑它们。这里有很多帖子在讨论如何向集合中添加或移除项,但没有关于如何编辑它们的内容。
所以在我的视图模型中有以下集合:
private ObservableCollection<ExerciseModel> exercises = new();
public ObservableCollection<ExerciseModel> Exercises
{
get { return exercises; }
set
{
exercises = value;
OnPropertyChanged();
}
}
ExerciseModel实现了INotifyPropertyChanged,并将初始值放入项中:
public class ExerciseModel: INotifyPropertyChanged
{
private static readonly int maxWeights = 5;
public string IdExercise { get; set; } = string.Empty;
public string IdExerciseSet { get; set; } = string.Empty;
public string ExerciseName { get; set; } = string.Empty;
public ObservableCollection<string> exerciseWeights = new();
public ObservableCollection<string> ExerciseWeights
{
get { return exerciseWeights; }
set { exerciseWeights = value; OnPropertyChanged(); }
}
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ExerciseModel()
{
for (int i = 0; i < maxWeights; i++)
{
ExerciseWeights.Add("10");
}
}
}
对我来说有点难理解的部分是这个。我不太确定如何将绑定绑定到TextBox。我的做法是这样的(使用Binding Path=. ):
<ItemsControl Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="7" Grid.RowSpan="5" VerticalAlignment="Top" ItemsSource="{Binding Exercises}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Width="75" Text="{Binding ExerciseName}"/>
<ItemsControl ItemsSource="{Binding ExerciseWeights}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBox Width="30" Text="{Binding Path=.}"/>
<!-- Path=. Not really sure if this is the right way to bind -->
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
这样的项控件显示正确。默认值会显示出来,但当我修改其中任意一个值时,它们不会在我的视图模型中更新。这里可能出了什么问题?
解决方案
在WPF中,没有一种可靠的方式来修改单一值对象(例如int、string等)。
唯一的办法是删除并重新添加项以实现刷新。但在这种情况下不可选,因为TextBox的更新频率太高,没必要这么做;而且集合可能也不会移除那个值,因为它们会指向同一个实例。
更好的做法是创建一个具有单一值属性的新可观察类(你可以将其泛化以适用于更多不同的用途)。
我给出一个实现的简单示例
在C#中:
//Implementing interface for updating data on change
public class MutableStringValue : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null!)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
//String value to change
public string Value
{
get { return field; }
set { field = value; OnPropertyChanged(); }
}
public MutableStringValue(string value)
{
Value = value;
}
}
//Here's i don't implement INotifyPropertyChanged since i don't have any observable property
public class ViewModel
{
//Setting OnPropertyChanged() for ObservableCollection isn't necessary: collection itself notify about items adds/removals
//But it doesn't if we're changing properties of an item thus we make it observable too
public ObservableCollection<MutableStringValue> Items { get; } = new ObservableCollection<MutableStringValue>()
{
new MutableStringValue("10")
};
}
在XAML中:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Value}"/>
<TextBox Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。