如何在视图中编辑可观察集合中的项

编程语言 2026-07-12

在我的应用程序中,我正在显示一个可观察集合中的项,并希望用户能够编辑它们。这里有很多帖子在讨论如何向集合中添加或移除项,但没有关于如何编辑它们的内容。

所以在我的视图模型中有以下集合:

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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章