【问题标题】:WPF Datagrid for IList<String> - cannot add new valuesIList<String> 的 WPF Datagrid - 无法添加新值
【发布时间】:2018-12-23 10:57:18
【问题描述】:

我有一个 JSON 模型和一个 IList 下属。

没什么特别的,我想将它们放入一个数据网格中,用户可以在其中添加和删除该列表中的值。

所以首先我遇到了唯一的长度列问题,因为显然 C# 觉得选择属性很有趣,而这恰好是长度。

所以我通过另一个解释这一点的堆栈溢出解决了这个问题。

<DataGrid ItemsSource="{Binding Path=Job.Subordinates, UpdateSourceTrigger=PropertyChanged}" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto"  Height="Auto" HorizontalAlignment="Left" Grid.Column="1" AutoGenerateColumns="False" >
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Subordinate Id">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding}"></TextBlock>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

但是,现在最终结果是只读的 DataGrid。如果我加载 JSON,则无法添加新行或编辑现有行。

为什么会发生这种行为?

编辑:json 对象及其字段

using GalaSoft.MvvmLight;
using System;
using System.Collections.Generic;

namespace GalaxyCreator.Model.Json
{
    public class Job : ObservableObject
    {
        private String _id;
        public String Id
        {
            get { return _id; }
            set
            {
                Set(ref _id, value);
            }
        }

        private String _name;
        public String Name
        {
            get { return _name; }
            set
            {
                Set(ref _name, value);
            }
        }

        private Boolean _startActive;
        public Boolean StartActive
        {
            get { return _startActive; }
            set
            {
                Set(ref _startActive, value);
            }
        }

        private Boolean _disabled;
        public Boolean Disabled
        {
            get { return _disabled; }
            set
            {
                Set(ref _disabled, value);
            }
        }

        private Boolean _rebuild;
        public Boolean Rebuild
        {
            get { return _rebuild; }
            set
            {
                Set(ref _rebuild, value);
            }
        }

        private Boolean _comandeerable;
        public Boolean Commandeerable
        {
            get { return _comandeerable; }
            set
            {
                Set(ref _comandeerable, value);
            }
        }

        private Boolean _subordinate;
        public Boolean Subordinate
        {
            get { return _subordinate; }
            set
            {
                Set(ref _subordinate, value);
            }
        }

        private bool _buildatshipyard = true;
        public bool Buildatshipyard
        {
            get { return _buildatshipyard; }
            set
            {
                Set(ref _buildatshipyard, value);
            }
        }

        private JobLocation _jobLocation = new JobLocation();
        public JobLocation JobLocation
        {
            get { return _jobLocation; }
            set
            {
                Set(ref _jobLocation, value);
            }
        }

        private JobCategory _jobCategory = new JobCategory();
        public JobCategory JobCategory
        {
            get { return _jobCategory; }
            set
            {
                Set(ref _jobCategory, value);
            }
        }

        private JobQuota _jobQuota = new JobQuota();
        public JobQuota JobQuota
        {
            get { return _jobQuota; }
            set
            {
                Set(ref _jobQuota, value);
            }
        }

        private IList<JobOrder> _orders = new List<JobOrder>();
        public IList<JobOrder> Orders
        {
            get { return _orders; }
            set
            {
                Set(ref _orders, value);
            }
        }

        private String _basket;
        public String Basket
        {
            get { return _basket; }
            set
            {
                Set(ref _basket, value);
            }
        }

        private String _encounters;
        public String Encounters
        {
            get { return _encounters; }
            set
            {
                Set(ref _encounters, value);
            }
        }

        private String _time;
        public String Time
        {
            get { return _time; }
            set
            {
                Set(ref _time, value);
            }
        }
        private Ship _ship = new Ship();
        public Ship Ship
        {
            get { return _ship; }
            set
            {
                Set(ref _ship, value);
            }
        }

        private IList<String> _subordinates = new List<String>();
        public IList<String> Subordinates
        {
            get { return _subordinates; }
            set
            {
                Set(ref _subordinates, value);
            }
        }
    }
}

编辑:我尝试了一种新方法但仍然没有运气,这次我尝试包装字符串

包装器

public class SubordinateItem : ObservableObject
{
    private String _value = default(String);

    public SubordinateItem(string subordinate)
    {
        this._value = subordinate;
    }

    public String Value
    {
        get { return _value; }
        set
        {
            if (value != _value)
            {
                _value = value;
                Set(ref _value, value);
            }
        }
    }
}

视图模型

class JobEditorDetailViewModel : DialogViewModelBase
{
    public Job Job { get; set; }

    private ObservableCollection<SubordinateItem> _subordinateItems = new ObservableCollection<SubordinateItem>();
    public ObservableCollection<SubordinateItem> SubordinateItems
    {
        get { return _subordinateItems; }
        set
        {                
            this.Job.Subordinates.Clear();
            foreach (SubordinateItem item in value)
            {
                this.Job.Subordinates.Add(item.Value);
            }
            Set(ref _subordinateItems, value);
        }
    }

    public JobEditorDetailViewModel(string message, Job job) : base(message)
    {
        this.Job = job;
        this._saveCommand = new RelayCommand<object>((parent) => OnSaveClicked(parent));
        this._cancelCommand = new RelayCommand<object>((parent) => OnCancelClicked(parent));
        foreach(String subordinate in Job.Subordinates)
        {
            _subordinateItems.Add(new SubordinateItem(subordinate));
        }
    }
}

XAML

                <DataGrid ItemsSource="{Binding SubordinateItems, NotifyOnTargetUpdated=True}" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" 
                          ScrollViewer.HorizontalScrollBarVisibility="Auto" Height="Auto" Grid.Row="1" AutoGenerateColumns="False" HorizontalAlignment="Left" Width="572" >
                    <DataGrid.Columns>
                        <DataGridTextColumn Binding="{Binding Value, UpdateSourceTrigger=PropertyChanged}" Width="500" Header="Subordinate Id" IsReadOnly="false" />
                    </DataGrid.Columns>
                </DataGrid>

【问题讨论】:

  • 你绑定什么字段? Text="{Binding}" 表示绑定到整个对象。
  • 为了清楚起见,我将添加 json 对象,但这就是其他 stackoverflow 帖子所说的我可以解决“仅显示长度属性”的方法。我刚刚意识到我忘了提到这是使用 MVVM light 作为框架

标签: c# wpf mvvm mvvm-light


【解决方案1】:

所以在长时间编写各种 hack 尝试修复它之后,我得到了以下设置的解决方案

public class SubordinateItem : ObservableObject
{
    private String _value = default(String);

    public SubordinateItem() { }

    public SubordinateItem(string subordinate)
    {
        this._value = subordinate;
    }

    public String Value
    {
        get { return _value; }
        set
        {
            if (value != _value)
            {
                _value = value;
                Set(ref _value, value);
            }
        }
    }
}

注意没有参数的公共构造函数,这是向数据网格添加新项目所必需的。没有它,它就不能为它实例化新对象。这是视图模型

class JobEditorDetailViewModel : DialogViewModelBase
{
    public Job Job { get; set; }

    private RelayCommand<object> _saveCommand = null;
    public RelayCommand<object> SaveCommand
    {
        get { return _saveCommand; }
        set { _saveCommand = value; }
    }

    private RelayCommand<object> _cancelCommand = null;
    public RelayCommand<object> CancelCommand
    {
        get { return _cancelCommand; }
        set { _cancelCommand = value; }
    }

    private IList<SubordinateItem> _subordinateItems = new List<SubordinateItem>();
    public IList<SubordinateItem> SubordinateItems
    {
        get { return _subordinateItems; }
        set
        {
            Set(ref _subordinateItems, value);
        }
    }

    public JobEditorDetailViewModel(string message, Job job) : base(message)
    {
        this.Job = job;
        this._saveCommand = new RelayCommand<object>((parent) => OnSaveClicked(parent));
        this._cancelCommand = new RelayCommand<object>((parent) => OnCancelClicked(parent));
        foreach (String subordinate in Job.Subordinates)
        {
            _subordinateItems.Add(new SubordinateItem(subordinate));
        }
    }

    private void OnSaveClicked(object parameter)
    {
        this.Job.Subordinates.Clear();
        foreach (SubordinateItem item in _subordinateItems)
        {
            this.Job.Subordinates.Add(item.Value);
        }
        this.CloseDialogWithResult(parameter as Window, DialogResult.Yes);
    }

    private void OnCancelClicked(object parameter)
    {
        this.CloseDialogWithResult(parameter as Window, DialogResult.No);
    }
}

因此,在视图模型的构造函数中,我从 json 对象 Job.Subordinates 中获取数据,该对象是 String 的 IList,并将其包装在 SubordinateItem 中并将其存储在 _subordinateItems 中。数据网格与此绑定并将使用它。然后我有一个保存按钮,后面有一个命令,我在其中执行相反的操作。我将 DataGrid 在 _subordinateItems 中的所有内容放回 json 对象中。我似乎无法将数据网格直接绑定到字符串的 json 对象 IList

Xaml 相关部分

                <Label Content="Subordinates" />
                <DataGrid ItemsSource="{Binding SubordinateItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                          ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" 
                          ScrollViewer.HorizontalScrollBarVisibility="Auto" 
                          Height="Auto" Grid.Row="1" 
                          AutoGenerateColumns="False" 
                          HorizontalAlignment="Left" 
                          Width="572" SelectionMode="Single">
                    <DataGrid.Columns>
                        <DataGridTextColumn Binding="{Binding Value, UpdateSourceTrigger=PropertyChanged}" Width="500" Header="Subordinate Id" IsReadOnly="false" />
                    </DataGrid.Columns>
                </DataGrid>

【讨论】:

    猜你喜欢
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 2011-11-19
    相关资源
    最近更新 更多