gpt4 book ai didi

c# - 此 View 不允许使用 WPF 'EditItem'

转载 作者:行者123 更新时间:2023-11-30 23:08:53 25 4
gpt4 key购买 nike

我知道有很多关于该错误的问题(12345 等),但我找不到可以解释原因的问题这个错误适合我的情况。如果我错过了一个,请告诉我!

首先,我绑定(bind)到我的 DataGrid ItemsSource使用自定义类(不是 ObservableCollection 或任何其他 .NET 内置可观察集合)。在向您展示它的代码之前,让我解释一下我是如何想到它的(我的假设可能是错误的)。

在我看来,要可绑定(bind),集合必须至少实现 IEnumerable。和 INotifyCollectionChanged . IEnumerable 以便 View 获取要显示的项目(感谢 GetEnumerator 方法)和 INotifyCollectionChanged 以便 View 了解集合的更改。

所以我最终得到了这门课:

public class ObservableDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IEnumerable<TValue>, INotifyCollectionChanged
{
#region fields

private IDictionary<TKey, TValue> _innerDictionary;

#endregion

#region properties

public int Count { get { return _innerDictionary.Count; } }

public ICollection<TKey> Keys { get { return _innerDictionary.Keys; } }

public ICollection<TValue> Values { get { return _innerDictionary.Values; } }

public bool IsReadOnly { get { return false; } }

#endregion

#region indexors

public TValue this[TKey key]
{
get { return _innerDictionary[key]; }
set { this.InternalAdd(new KeyValuePair<TKey, TValue>(key, value)); }
}

#endregion

#region events

public event NotifyCollectionChangedEventHandler CollectionChanged;

#endregion

#region constructors

public ObservableDictionary()
{
_innerDictionary = new Dictionary<TKey, TValue>();
}

public ObservableDictionary(int capacity)
{
_innerDictionary = new Dictionary<TKey, TValue>(capacity);
}

public ObservableDictionary(IEqualityComparer<TKey> comparer)
{
_innerDictionary = new Dictionary<TKey, TValue>(comparer);
}

public ObservableDictionary(IDictionary<TKey, TValue> dictionary)
{
_innerDictionary = new Dictionary<TKey, TValue>(dictionary);
}

public ObservableDictionary(int capacity, IEqualityComparer<TKey> comparer)
{
_innerDictionary = new Dictionary<TKey, TValue>(capacity, comparer);
}

public ObservableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
{
_innerDictionary = new Dictionary<TKey, TValue>(dictionary, comparer);
}

#endregion

#region public methods

public bool ContainsKey(TKey key)
{
return _innerDictionary.ContainsKey(key);
}

public bool Contains(KeyValuePair<TKey, TValue> item)
{
return _innerDictionary.Contains(item);
}

public void Add(TKey key, TValue value)
{
this.InternalAdd(new KeyValuePair<TKey, TValue>(key, value));
}

public void AddRange(IEnumerable<KeyValuePair<TKey, TValue>> items)
{
if (!items.Any())
{
return;
}

var added = new List<TValue>();
var removed = new List<TValue>();

foreach (var item in items)
{
TValue value;
if (_innerDictionary.TryGetValue(item.Key, out value))
{
removed.Add(value);
}

added.Add(item.Value);
_innerDictionary[item.Key] = item.Value;
}

this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, added, null));

if (removed.Count > 0)
{
this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, null, removed));
}
}

public void Add(KeyValuePair<TKey, TValue> item)
{
this.InternalAdd(item);
}

public bool TryGetValue(TKey key, out TValue value)
{
return _innerDictionary.TryGetValue(key, out value);
}

public bool Remove(TKey key)
{
return this.InternalRemove(key);
}

public bool Remove(KeyValuePair<TKey, TValue> item)
{
return this.InternalRemove(item.Key);
}

public void Clear()
{
_innerDictionary.Clear();
this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}

public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
_innerDictionary.CopyTo(array, arrayIndex);
}

public IEnumerator<TValue> GetEnumerator()
{
return Values.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}

IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
{
return _innerDictionary.GetEnumerator();
}

#endregion

#region private methods

/// <summary>
/// Adds the specified value to the internal dictionary and indicates whether the element has actually been added. Fires the CollectionChanged event accordingly.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
private void InternalAdd(KeyValuePair<TKey, TValue> item)
{
IList added = new TValue[] { item.Value };

TValue value;
if (_innerDictionary.TryGetValue(item.Key, out value))
{
this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, null, new TValue[] { value }));
}

_innerDictionary[item.Key] = item.Value;
this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, added, null));
}

/// <summary>
/// Remove the specified key from the internal dictionary and indicates whether the element has actually been removed. Fires the CollectionChanged event accordingly.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
private bool InternalRemove(TKey key)
{
TValue value;
if (_innerDictionary.TryGetValue(key, out value))
{
_innerDictionary.Remove(key);
this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, null, new TValue[] { value }));
}

return value != null;
}

#endregion
}

它隐式实现了 IEnumerable<TValue>.GetEnumerator并明确其他人 GetEnumerator方法( IDictionaryIEnumerable )以便我的 View 仅显示我的字典的值,并且我将添加/删除方法映射到 CollectionChanged 的调用周围事件。

我的 ViewModel 是这样定义的:

class MyViewModel
{
public ObservableDictionary<string, Foo> Foos { get; private set; }

public MyViewModel()
{
this.Foos = new ObservableDictionary<string, Foo>();
}
}

然后像这样将它绑定(bind)到我的 View :

<DataGrid ItemsSource="{Binding Facts}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" IsReadOnly="True" Width="*" />
<DataGridTextColumn Header="Type" Binding="{Binding Type}" IsReadOnly="True" Width="*" />
<DataGridTextColumn Header="Value" Binding="{Binding Value}" IsReadOnly="False" Width="*" />
</DataGrid.Columns>
</DataGrid>

然后,当我尝试编辑值时,出现指定的错误:

'EditItem' is not allowed for this view

当我在我的代码中放置一些断点时,我永远不会到达 ObservableDictionary indexor setter nor Foo.Value二传手。

关于 View 如何从绑定(bind)集合中获取项目的想法是否正确?为什么会出现此错误和/或如何将我的 View 授权给 EditItem ?

最佳答案

您的源集合类型 ( ObservableDictionary<TKey, TValue> ) 应该实现 IList界面,如果你想能够编辑 DataGrid 中的数据.

每当您绑定(bind)到 WPF 中的某些集合属性时,您总是绑定(bind)到一个自动生成的 View ,而不是实际的源集合本身。

运行时为您创建的 View 类型取决于源集合的类型,您的源集合必须实现非泛型 IList DataGrid 的内部编辑功能界面控制工作。

关于c# - 此 View 不允许使用 WPF 'EditItem',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46241564/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com