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

如何在WPF视图中正确绑定并显示ObservableCollection数组条目?

问题描述

我写了一个读取XML数据并存入ObservableCollection的程序,现在有两个存储string数组的ObservableCollection,希望在ListView的两列中分别展示这两个数组的数据。最初直接调用ListView的Add方法添加数据,虽能显示但无法对条目进行操作(如选择值计算平均值),于是尝试实现MVVM模式,但无法正确绑定字段,导致ObservableCollection新增条目时视图无法更新。

XAML代码

<views:MvxWpfView
    x:Class="Ui.MVVMMaPa.Views.HomeView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:views="clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Ui.MVVMMaPa.Views" xmlns:core="clr-namespace:Ui.MVVMMaPa.Core" d:DataContext="{d:DesignInstance Type=core:HomeViewModel}"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <StackPanel>
            <TextBox Text="{Binding Text,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            <Button Content="Browse" Command="{Binding BrowseCommand}" />
            
            <ListBox Name="ListBox">
                <TextBlock Name="TextBlockName" Text="{Binding ShortNameStringObservableList}" />
                <TextBlock Name="TextBlockid" Text="{Binding ValueStringObservableList}"/>
            </ListBox>
            
        </StackPanel>
    </Grid>
</views:MvxWpfView>

ViewModel代码

using Logic.MVVMMaPa.ListCreater;
using MvvmCross.Commands;
using MvvmCross.ViewModels;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Ui.MVVMMaPa.Core
{
    public class HomeViewModel : MvxViewModel
    {
        public DirectoryIterator directoryIterator = new DirectoryIterator();
        private List<MachineparameterClass> machineparameterList = new List<MachineparameterClass>();
        public IMvxCommand BrowseCommand => new MvxCommand(Browse);

        private ObservableCollection<string[]> shortNameStringObservableList = new ObservableCollection<string[]>();
        public ObservableCollection<string[]> ShortNameStringObservableList
        {
            get { return shortNameStringObservableList; }
            set
            {
                shortNameStringObservableList = value;
                RaisePropertyChanged(() => nameof(ShortNameStringObservableList));
            }

        }
        private ObservableCollection<string[]> valueStringObservableList = new ObservableCollection<string[]>();

        public ObservableCollection<string[]> ValueStringObservableList
        {
            get => valueStringObservableList;
            set
            {
                valueStringObservableList = value;
                RaisePropertyChanged(() => nameof(ValueStringObservableList));
            }
        }
        private void Browse()
        {

            Comparer comparer = new Comparer(directoryIterator.FileIterationOne(directoryIterator.DirectoryIteratorFunction()));
            machineparameterList = comparer.ListComparer();

            for (int i = 0; i < machineparameterList.Count; i++)
            {
                ShortNameStringObservableList.Add(machineparameterList[i].getShortNames());
                ValueStringObservableList.Add(machineparameterList[i].getValues());
            }
        }
    }
}

Model代码

using System.ComponentModel;


namespace Logic.MVVMMaPa.ListCreater
{
    public class MachineparameterClass : INotifyPropertyChanged
    {
        string pluginName;
        string pluginInstanceName;
        string[] shortNames;
        string[] values;
        string[] typesInInt;

        public event PropertyChangedEventHandler? PropertyChanged;
        void OnPropertyChanged(string name) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        public string PluginName
        {
            get { return pluginName; }
            set { pluginName = value; }
        }
        public string PluginInstanceName
        {
            get { return pluginInstanceName; }
            set { pluginInstanceName = value; OnPropertyChanged(nameof(PluginInstanceName)); }
        }
        public string[] ShortNames
        {
            get { return shortNames; }
            set { shortNames = value; OnPropertyChanged(nameof(ShortNames)); }
        }
        public string[] Values
        {
            get { return values; }
            set { values = value; OnPropertyChanged(nameof(Values)); }
        }
        public string[] TypesInInt
        {
            get { return typesInInt; }
            set { typesInInt = value; OnPropertyChanged(nameof(TypesInInt)); }
        }


        public MachineparameterClass()
        {
        }

        public MachineparameterClass(MachineparameterClass machineparameterClass)
        {
            this.pluginName = pluginName;
            this.pluginInstanceName = pluginInstanceName;
            this.shortNames = shortNames;
            this.values = values;
            this.typesInInt = typesInInt;

        }
        public void SetProperty(string prop, string val)
        {

        }
        public MachineparameterClass(string pluginName, string pluginInstanceName, string[] shortNames, string[] values, string[] typesInInt) : base()
        {
            this.pluginName = pluginName;
            this.pluginInstanceName = pluginInstanceName;
            this.shortNames = shortNames;
            this.values = values;
            this.typesInInt = typesInInt;
        }

        public String getPluginName() { return this.PluginName; }
        public String getPluginInstanceName() { return this.PluginInstanceName; }
        public String[] getShortNames() { return this.ShortNames; }
        public String[] getValues() { return this.Values; }
        public String[] getTypes() { return this.typesInInt; }
    }
}
解决方案

1. 重构ViewModel,使用单一集合存储完整模型

当前两个独立的ObservableCollection会导致数据关联混乱,直接使用ObservableCollection<MachineparameterClass>存储所有数据,因为MachineparameterClass本身已包含ShortNames和Values数组,更符合MVVM设计逻辑:

// 替换原来的两个ObservableCollection
private ObservableCollection<MachineparameterClass> _machineParameters = new ObservableCollection<MachineparameterClass>();
public ObservableCollection<MachineparameterClass> MachineParameters
{
    get => _machineParameters;
    set
    {
        _machineParameters = value;
        RaisePropertyChanged(nameof(MachineParameters));
    }
}

private void Browse()
{
    Comparer comparer = new Comparer(directoryIterator.FileIterationOne(directoryIterator.DirectoryIteratorFunction()));
    var tempList = comparer.ListComparer();
    
    // 清空旧数据避免重复
    MachineParameters.Clear();
    foreach (var param in tempList)
    {
        MachineParameters.Add(param);
    }
}

2. 修正XAML布局,使用ListView+GridView实现两列展示

原来的ListBox绑定方式错误,改用ListView定义GridView列,通过数据模板展示数组内容:

<!-- 替换原ListBox -->
<ListView ItemsSource="{Binding MachineParameters}" Margin="10">
    <ListView.View>
        <GridView>
            <!-- 第一列:ShortNames数组 -->
            <GridViewColumn Header="短名称">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <ItemsControl ItemsSource="{Binding ShortNames}">
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <TextBlock Text="{Binding}" Margin="2"/>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <WrapPanel/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                        </ItemsControl>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>

            <!-- 第二列:Values数组 -->
            <GridViewColumn Header="数值">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <ItemsControl ItemsSource="{Binding Values}">
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <TextBlock Text="{Binding}" Margin="2"/>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <WrapPanel/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                        </ItemsControl>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

3. 完善Model的属性通知

当前Model的PluginName属性未触发PropertyChanged事件,补上以确保属性变更能通知视图:

public string PluginName
{
    get { return pluginName; }
    set 
    { 
        pluginName = value; 
        OnPropertyChanged(nameof(PluginName)); 
    }
}

同时建议移除Model中的getter方法(如getShortNames()),直接使用属性访问,符合C#编码规范。

4. 确认绑定正确性

  • MvvmCross通常会自动设置View的DataContext,确保导航逻辑正确;
  • ObservableCollection新增元素时会自动通知视图更新,无需额外调用RaisePropertyChanged(仅替换整个集合时需要)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 22:20:57