You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中如何用MVVM模式更新TerminalList视图并绑定ObservableCollection

WPF MVVM模式下TerminalList视图数据更新解决方案

核心问题处理思路

你已将List<Terminal>传入TerminalListViewModel,但需将其转换为ObservableCollection<TerminalViewModel>才能让视图自动感知集合变化。以下是具体修改步骤:


1. 修正TerminalListViewModel代码

正确接收传入的数据源,并实现UpdateTerminals方法完成数据转换:

namespace EMC.TerminalKonfigurator.ViewModels
{
    public class TerminalListViewModel : ViewModelBase
    {
        // 存储传入的原始Terminal数据源
        private readonly List<Terminal> _sourceTerminals;
        // 用于视图绑定的ObservableCollection(自带集合变化通知)
        private readonly ObservableCollection<TerminalViewModel> _terminals;
        // 对外暴露的只读集合属性,供视图绑定
        public IEnumerable<TerminalViewModel> Terminals => _terminals;
        public ICommand NavigateAddTerminalViewCommand { get; }

        public TerminalListViewModel(List<Terminal> terminals, Services.NavigationService addTerminalNavigationService) 
        {
            // 将构造函数传入的List赋值给私有字段
            _sourceTerminals = terminals;
            _terminals = new ObservableCollection<TerminalViewModel>();
            NavigateAddTerminalViewCommand = new NavigateAddTerminalViewCommand(addTerminalNavigationService);

            // 初始化加载数据
            UpdateTerminals();
        }

        private void UpdateTerminals()
        {
            // 清空现有集合避免重复数据
            _terminals.Clear();
            // 遍历原始数据源,转换为TerminalViewModel并添加到ObservableCollection
            foreach (var terminal in _sourceTerminals)
            {
                _terminals.Add(new TerminalViewModel(terminal));
            }
        }
    }
}

2. 实现TerminalViewModel包装类

TerminalViewModel需继承ViewModelBase实现INotifyPropertyChanged,包装Terminal的属性以支持视图绑定:

namespace EMC.TerminalKonfigurator.ViewModels
{
    public class TerminalViewModel : ViewModelBase
    {
        private readonly Terminal _terminal;

        // 与视图绑定的属性,需和Terminal类的属性对应
        public string TerminalName => _terminal.TerminalName;
        public string Ip => _terminal.Ip;

        public TerminalViewModel(Terminal terminal)
        {
            _terminal = terminal;
        }
    }
}

注意:如果Terminal类的属性是小写(如terminalName、ip),请同步调整TerminalViewModel的属性名,保持与视图绑定字段一致。


3. 优化:支持数据源动态更新(可选)

若需添加新Terminal后自动更新视图,建议将App中的List<Terminal>替换为ObservableCollection<Terminal>,并监听集合变化:

修改App.xaml.cs:

namespace TerminalKonfigurator
{
    public partial class App : Application
    {
        // 替换为ObservableCollection,自带集合变化通知
        private readonly ObservableCollection<Terminal> _terminals;
        private readonly NavigationStore _navigationStore;

        public App()
        {
            Terminal terminal1 = new Terminal("Terminal1", "129,22,22,31");
            Terminal terminal2 = new Terminal("Terminal2", "129,22,22,32");
            _navigationStore = new NavigationStore();

            _terminals = new ObservableCollection<Terminal>();
            _terminals.Add(terminal1);
            _terminals.Add(terminal2);
        }

        private AddTerminalViewModel createAddTerminalViewModel()
        {
            return new AddTerminalViewModel(_terminals, new Services.NavigationService(_navigationStore, createTerminalListViewModel));
        }

        private TerminalListViewModel createTerminalListViewModel()
        {
            return new TerminalListViewModel(_terminals, new Services.NavigationService(_navigationStore, createAddTerminalViewModel));
        }

        protected override void OnStartup(StartupEventArgs e)
        {
            _navigationStore.CurrentViewModel = createTerminalListViewModel();

            MainWindow = new MainWindow()
            {
                DataContext = new MainViewModel(_navigationStore)
            };
            MainWindow.Show();

            base.OnStartup(e);
        }
    }
}

修改TerminalListViewModel监听集合变化:

public TerminalListViewModel(ObservableCollection<Terminal> terminals, Services.NavigationService addTerminalNavigationService) 
{
    _sourceTerminals = terminals;
    _terminals = new ObservableCollection<TerminalViewModel>();
    NavigateAddTerminalViewCommand = new NavigateAddTerminalViewCommand(addTerminalNavigationService);

    UpdateTerminals();
    // 监听原始集合变化,高效更新视图集合
    _sourceTerminals.CollectionChanged += SourceTerminals_CollectionChanged;
}

private void SourceTerminals_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    switch (e.Action)
    {
        case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
            foreach (Terminal terminal in e.NewItems)
            {
                _terminals.Add(new TerminalViewModel(terminal));
            }
            break;
        case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
            foreach (Terminal terminal in e.OldItems)
            {
                var viewModel = _terminals.FirstOrDefault(vm => vm.TerminalName == terminal.TerminalName);
                if (viewModel != null)
                {
                    _terminals.Remove(viewModel);
                }
            }
            break;
        case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
            _terminals.Clear();
            UpdateTerminals();
            break;
    }
}

4. 视图绑定调整

确保ListView的ItemsSource绑定正确,且DataTemplate属性与TerminalViewModel一致:

<ListView Grid.Row="1" ItemsSource="{Binding Terminals}">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Terminalname">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <!-- 属性名需与TerminalViewModel保持一致 -->
                        <TextBlock Text="{Binding TerminalName}" HorizontalAlignment="Center"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn Header="IP-Adresse">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Ip}" HorizontalAlignment="Center"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

注:集合绑定无需额外设置UpdateSourceTrigger=PropertyChanged,ObservableCollection会自动触发变化通知。

内容的提问来源于stack exchange,提问作者Zxmod51

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 08:57:06