【问题标题】:Wpf ICollectionView Binding item cannot resolve property of type objectWpf ICollectionView 绑定项无法解析类型对象的属性
【发布时间】:2013-12-13 19:35:27
【问题描述】:

我在 XAML 设计器中绑定了 GridViewICollectionView 属性未知,因为 CollectionView 中的实体已转换为类型 Object 并且无法访问实体属性,它运行良好,没有错误,但设计器将其显示为错误,如果我绑定到集合,我可以正常访问属性

例如,实体是带有string Name 属性的Person 我将它们放在ObservableCollection<Person> 中并从中获取视图并将其绑定到GridView.ItemsSource 现在当我尝试设置列标题@987654330 @property 设计师将其显示为错误

无法解析类型对象的数据上下文中的属性“FirstName”

这是一个 bug 还是 Resharper 在捉弄我

示例代码:

public class Person 
{
    public string FirstName{
       get { return _firstName; }
       set { SetPropertyValue("FirstName", ref _firstName, value); }
    }
}
public class DataService 
{
    public IDataSource DataContext { get; set; }
    public ICollectionView PersonCollection{ get; set; }

    public DataService()
    {
        DataContext = new DataSource();
        //QueryableCollectionView is from Telerik 
        //but if i use any other CollectionView same thing
        //DataContext Persons is an ObservableCollection<Person> Persons
        PersonCollection = new QueryableCollectionView(DataContext.Persons);
    }
}

<telerik:RadGridView x:Name="ParentGrid" 
    ItemsSource="{Binding DataService.PersonCollection}"
    AutoGenerateColumns="False">
    <telerik:RadGridView.Columns >
        <telerik:GridViewDataColumn Header="{lex:Loc Key=FirstName}"  
            DataMemberBinding="{Binding FirstName}"/>
    </telerik:RadGridView.Columns>
</telerik:RadGridView>

【问题讨论】:

    标签: c# wpf xaml icollectionview


    【解决方案1】:

    您的实体尚未转换为对象,这是因为接口 ICollectionView 不是通用集合,因此 ReSharper 无法知道它包含 Person 的集合。

    您可以创建ICollectionView 的通用版本并将其用于您的PersonCollection 属性,如本文https://benoitpatra.com/2014/10/12/a-generic-version-of-icollectionview-used-in-a-mvvm-searchable-list/ 中所示。

    首先是一些接口:

    public interface ICollectionView<T> : IEnumerable<T>, ICollectionView
    {
    }
    
    public interface IEditableCollectionView<T> : IEditableCollectionView
    {
    }
    

    实现:

    public class GenericCollectionView<T> : ICollectionView<T>, IEditableCollectionView<T>
    {
        readonly ListCollectionView collectionView;
    
        public CultureInfo Culture
        {
            get => collectionView.Culture;
            set => collectionView.Culture = value;
        }
    
        public IEnumerable SourceCollection => collectionView.SourceCollection;
    
        public Predicate<object> Filter
        {
            get => collectionView.Filter;
            set => collectionView.Filter = value;
        }
    
        public bool CanFilter => collectionView.CanFilter;
    
        public SortDescriptionCollection SortDescriptions => collectionView.SortDescriptions;
    
        public bool CanSort => collectionView.CanSort;
    
        public bool CanGroup => collectionView.CanGroup;
    
        public ObservableCollection<GroupDescription> GroupDescriptions => collectionView.GroupDescriptions;
    
        public ReadOnlyObservableCollection<object> Groups => collectionView.Groups;
    
        public bool IsEmpty => collectionView.IsEmpty;
    
        public object CurrentItem => collectionView.CurrentItem;
    
        public int CurrentPosition => collectionView.CurrentPosition;
    
        public bool IsCurrentAfterLast => collectionView.IsCurrentAfterLast;
    
        public bool IsCurrentBeforeFirst => collectionView.IsCurrentBeforeFirst;
    
        public NewItemPlaceholderPosition NewItemPlaceholderPosition
        {
            get => collectionView.NewItemPlaceholderPosition;
            set => collectionView.NewItemPlaceholderPosition = value;
        }
    
        public bool CanAddNew => collectionView.CanAddNew;
    
        public bool IsAddingNew => collectionView.IsAddingNew;
    
        public object CurrentAddItem => collectionView.CurrentAddItem;
    
        public bool CanRemove => collectionView.CanRemove;
    
        public bool CanCancelEdit => collectionView.CanCancelEdit;
    
        public bool IsEditingItem => collectionView.IsEditingItem;
    
        public object CurrentEditItem => collectionView.CurrentEditItem;
    
        public event NotifyCollectionChangedEventHandler CollectionChanged
        {
            add => ((ICollectionView) collectionView).CollectionChanged += value;
            remove => ((ICollectionView) collectionView).CollectionChanged -= value;
        }
    
        public event CurrentChangingEventHandler CurrentChanging
        {
            add => ((ICollectionView) collectionView).CurrentChanging += value;
            remove => ((ICollectionView) collectionView).CurrentChanging -= value;
        }
    
        public event EventHandler CurrentChanged
        {
            add => ((ICollectionView) collectionView).CurrentChanged += value;
            remove => ((ICollectionView) collectionView).CurrentChanged -= value;
        }
    
        public GenericCollectionView([NotNull] ListCollectionView collectionView)
        {
            this.collectionView = collectionView ?? throw new ArgumentNullException(nameof(collectionView));
        }
    
        public IEnumerator<T> GetEnumerator()
        {
            return (IEnumerator<T>) ((ICollectionView) collectionView).GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((ICollectionView) collectionView).GetEnumerator();
        }
    
        public bool Contains(object item)
        {
            return collectionView.Contains(item);
        }
    
        public void Refresh()
        {
            collectionView.Refresh();
        }
    
        public IDisposable DeferRefresh()
        {
            return collectionView.DeferRefresh();
        }
    
        public bool MoveCurrentToFirst()
        {
            return collectionView.MoveCurrentToFirst();
        }
    
        public bool MoveCurrentToLast()
        {
            return collectionView.MoveCurrentToLast();
        }
    
        public bool MoveCurrentToNext()
        {
            return collectionView.MoveCurrentToNext();
        }
    
        public bool MoveCurrentToPrevious()
        {
            return collectionView.MoveCurrentToPrevious();
        }
    
        public bool MoveCurrentTo(object item)
        {
            return collectionView.MoveCurrentTo(item);
        }
    
        public bool MoveCurrentToPosition(int position)
        {
            return collectionView.MoveCurrentToPosition(position);
        }
    
        public object AddNew()
        {
            return collectionView.AddNew();
        }
    
        public void CommitNew()
        {
            collectionView.CommitNew();
        }
    
        public void CancelNew()
        {
            collectionView.CancelNew();
        }
    
        public void RemoveAt(int index)
        {
            collectionView.RemoveAt(index);
        }
    
        public void Remove(object item)
        {
            collectionView.Remove(item);
        }
    
        public void EditItem(object item)
        {
            collectionView.EditItem(item);
        }
    
        public void CommitEdit()
        {
            collectionView.CommitEdit();
        }
    
        public void CancelEdit()
        {
            collectionView.CancelEdit();
        }
    }
    

    最后是用法:

    ICollectionView<Person> PersonCollectionView { get; }
    

    在构造函数中:

    var view = (ListCollectionView) CollectionViewSource.GetDefaultView(PersonCollection);
    PersonCollectionView = new GenericCollectionView<Person>(view);
    

    【讨论】:

      【解决方案2】:

      两者都不是 d:DataContext="{d:DesignInstance Type=lcl:ViewModel}"> 也不 通用集合视图 直接适用于具有 CollectionViewSource 的 DataGrid。

          <DataGrid AutoGenerateColumns="False"
                    ItemsSource="{Binding collectionViewSource.View}" 
                    SelectedItem="{Binding SelectedRow}" 
      

      我们不能设置“d:DataContext”;因为,我们经常需要将多个属性绑定到我们的视图模型。

      CollectionViewSource 会创建新的 ListCollectionView,它会在您每次设置 Source 属性时在运行时实例化。由于设置 Source 属性是刷新一系列行的唯一合理方法,因此我们不能保留 GenericCollectionView。

      我的解决方案可能非常明显,但我放弃了 CollectionViewSource。通过创建属性

      private ObservableCollection<ListingGridRow> _rowDataStoreAsList;
      public GenericCollectionView<ListingGridRow> TypedCollectionView
      {
        get => _typedCollectionView;
        set { _typedCollectionView = value; OnPropertyChanged();}
      }
      
      public void FullRefresh()
      {
          var listData = _model.FetchListingGridRows(onlyListingId: -1);
          _rowDataStoreAsList = new ObservableCollection<ListingGridRow>(listData);
          var oldView = TypedCollectionView;
          var saveSortDescriptions = oldView.SortDescriptions.ToArray();
          var saveFilter = oldView.Filter;
          TypedCollectionView = new GenericCollectionView<ListingGridRow>(new ListCollectionView(_rowDataStoreAsList));
          var newView = TypedCollectionView;
          foreach (var sortDescription in saveSortDescriptions)
          {
              newView.SortDescriptions.Add(new SortDescription()
              {
                  Direction = sortDescription.Direction,
                  PropertyName = sortDescription.PropertyName
              });
          }
          newView.Filter = saveFilter;
      }
      internal void EditItem(object arg)
      {
          var view = TypedCollectionView;
          var saveCurrentPosition = view.CurrentPosition;
          var originalRow = view.TypedCurrentItem;
          if (originalRow == null)
              return;
          var listingId = originalRow.ListingId;
          var rawListIndex = _rowDataStoreAsList.IndexOf(originalRow);
          // ... ShowDialog ... DialogResult ...
          var lstData = _model.FetchListingGridRows(listingId);
          _rowDataStoreAsList[rawListIndex] = lstData[0];
          view.MoveCurrentToPosition(saveCurrentPosition);
          view.Refresh();
      }
      

      添加后 public T TypedCurrentItem => (T)collectionView.CurrentItem; 到Maxence提供的GenericCollectionView。

      【讨论】:

        【解决方案3】:

        Resharper 在 XAML 视图中给您的警告是因为控件的设计时视图不知道它的数据上下文是什么类型。您可以使用 d:DesignInstance 来帮助您进行绑定。

        添加以下内容(适当地替换程序集/命名空间/绑定目标名称)

        <UserControl x:Class="MyNamespace.UserControl1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup‐compatibility/2006"
        mc:Ignorable="d"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:lcl="clr‐namespace:MyAssembly"
        d:DataContext="{d:DesignInstance Type=lcl:ViewModel}">
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-06-14
          • 1970-01-01
          • 2012-02-20
          • 2011-09-11
          • 2012-07-20
          • 2020-04-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多