【问题标题】:Limit the Properties Bound to DataGrid in WPF using MVVM使用 MVVM 限制 WPF 中绑定到 DataGrid 的属性
【发布时间】:2013-05-16 17:39:21
【问题描述】:

所有,一个简单的问题。我有一个带有 DataGrid 的 MVVM 应用程序,我已使用

将其绑定到 ViewModel
<DataGrid ItemsSource="{Binding Path=Resources}" ...></DataGrid>

Resources 是通过

定义的
public ObservableCollection<ResourceViewModel> Resources { get; private set; }

然而,在ResourceViewModel 类中,我不仅有我想出现在DataGrid 中的属性,还有我不想 出现在DataGrid 中的其他属性。 ResourceViewmodel 类是

public class ResourceViewModel : WorkspaceViewModel, IDataErrorInfo
{
    readonly Resource resource;
    readonly ResourceDataRepository resourceRepository;
    private bool isSelected;

    public ResourceViewModel(Resource resource, ResourceDataRepository resourceRepository)
    {
        if (resource == null)
            throw new ArgumentNullException("resource");
        if (resourceRepository == null)
            throw new ArgumentNullException("resourceRepository");
        this.resource = resource;
        this.resourceRepository = resourceRepository;
    }

    public string KeyIndex 
    { 
        get { return this.resource.KeyIndex; } 
        set 
        {
            if (value == this.resource.KeyIndex)
                return;
            this.resource.KeyIndex = value;
            base.OnPropertyChanged("KeyIndex");
        }
    }

    public string FileName
    {
        get { return this.resource.FileName; }
        set 
        {
            if (value == this.resource.FileName)
                return;
            this.resource.FileName = value;
            base.OnPropertyChanged("FileName");
        }
    }

    public List<string> ResourceStringList
    {
        get { return this.resource.ResourceStringList; }
        set 
        {
            if (Utilities.Utilities.ScrambledEquals<string>(this.resource.ResourceStringList, value))
                return;
            this.resource.ResourceStringList = value;
            base.OnPropertyChanged("ResourceStringList");
        }
    }

    public bool IsSelected
    {
        get { return isSelected; }
        set
        {
            if (value == isSelected)
                return;
            isSelected = value;
            base.OnPropertyChanged("IsSelected");
        }
    }
}

我不希望IsSelected 出现在DataGrid 中并且我希望ResourceStringList 中的每个项目出现在Datagrid 的不同列中。我的问题是:

1.如何防止IsSelectedDataGrid 中显示[作为Checkbox]?

2。如何绑定到DataGrid 以自动在单独的列中显示项目?

你有什么尝试:

  1. 我试图从ResourceViewmodel 类继承并绑定到它,但这很恶心,我想要另一个更优雅的解决方案;请:]。

  2. 我不知道如何继续这个。 List 中存储的项目数是可变的,并在运行时设置 - 所以这需要是 List

一如既往,非常感谢您抽出宝贵时间。

【问题讨论】:

  • 您可以手动创建自己的列。请参阅DataGrid.AutoGenerateColumns 了解更多信息。
  • 如果每行 ResourceStringList 中的项目数不同,您要生成多少列,它们的标题应该是什么?
  • 当人们在 MVVM 模式中使用 ObservableCollection 时,我总是感到困惑。我认为如果您使用 MVVM 就没有必要……而且我真的从来不需要它,因为没有它总是有解决方案。 ://

标签: c# wpf mvvm binding datagrid


【解决方案1】:

对我来说,不自动生成列更容易。但这是个人喜好,所以我认为不允许暴露某些属性的最简单方法是使用接口的强大功能:)

  1. 绑定到 IResourceViewModel 的 ObservableCollection - 使 Resources 属性成为接口列表而不是具体类型
  2. 使 ResourceViewModel 实现 IResourceViewModel
  3. 在 IResourceViewModel 中,从界面中删除您不希望对网格可见的属性

【讨论】:

  • 虽然这会限制属性,但也意味着您不会获得自动添加新功能(当然假设您想要),因为 T 不是可创建的类型,因此您必须使用BindingList 并自己处理AddingNew 或实现IEditableCollectionView 或IBindingList。
  • true(在某种程度上 - 让事情开箱即用),这就是为什么我在发布我的方法之前给你的方法 +1。然而,在视图模型中使用 Add 命令并处理 List 操作也可以解决问题
【解决方案2】:

我认为选项是像 Silvermind 提到的那样关闭自动生成(即将 DataGrid.AutoGenerateColumns 设置为 false,然后定义列)或实现 ITypedList。例如,您可以创建一个派生的 ObservableCollection,它实现 ITypedList 并根据您放置在要隐藏的属性上的某些属性返回属性。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        this.DataContext = new TypedListObservableCollection<Foo>();

        InitializeComponent();
    }
}

public class TypedListObservableCollection<T> : ObservableCollection<T>
    , ITypedList
{
    public TypedListObservableCollection()
    {
    }

    PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors)
    {
        return TypeDescriptor.GetProperties(typeof(T), new Attribute[] { BrowsableAttribute.Yes });
    }

    string ITypedList.GetListName(PropertyDescriptor[] listAccessors)
    {
        return typeof(T).Name;
    }
}

public class Foo
{
    public string Name
    {
        get;
        set;
    }

    [Browsable(false)]
    public bool IsSelected
    {
        get;
        set;
    }
}

【讨论】:

  • +1 感谢您的帮助。您能否就如何使用我的List&lt;string&gt; ResourceStringList 中的条目填充DataGrid 列提供任何建议,因为目前DataGrid 仅显示一个带有“(集合)”的列。有人提到从List&lt;string&gt; 获得的列会得到什么标题:有没有办法也提供这个?非常感谢您的宝贵时间...
  • 正如@LPL 指出的那样,如果 ResourceStringList 至少在理论上每个数据项可以有不同数量的项目并且必须为所有数据项定义列,那么您怎么知道要提供多少列项目?如果您知道最大项目数并希望为每个项目生成一列,那么理论上您可以创建一个派生的 PropertyDescriptor 来表示每一列并返回从 GetItemProperties 返回的 PropertyDescriptorCollection 中的那些。
  • 我不知道 DataGrid 在添加/删除列时是否响应,但如果是这样并且您需要,那么您需要编写自己的自定义 IBindingList 实现并在添加/删除列时引发 ListChanged .
  • 我已经离开了。现在只是实施你的答案。我现在有我的public TypedListObservableCollection&lt;ResourceDataViewModel&gt; Resources { get; private set; } 访问器,我绑定到DataGrid。但是,在它是 ObservableCollection 之前,我通过:this.Resources = new ObservableCollection&lt;ResourceViewModel&gt;(resViewModelList); 将项目添加到 Resources,但现在我该怎么做才能添加到 TypedListObservableCollection
  • @Killercam,我不明白这个问题。 TypedListObservableCollection 只是从 ObservableCollection 派生的,因此它可以完全按照您使用 OC 的方式使用,因为它是一个 OC
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-07
  • 1970-01-01
  • 1970-01-01
  • 2017-10-29
  • 2014-12-29
  • 2015-11-21
相关资源
最近更新 更多