ReadOnlyObservableCollection.CollectionChanged
보호되고 공개되지 않는 이유는 무엇입니까 (해당하는대로 ObservableCollection.CollectionChanged
)?
이벤트에 INotifyCollectionChanged
액세스 할 수없는 경우 구현하는 컬렉션의 용도는 무엇입니까 CollectionChanged
?
ReadOnlyObservableCollection.CollectionChanged
보호되고 공개되지 않는 이유는 무엇입니까 (해당하는대로 ObservableCollection.CollectionChanged
)?
이벤트에 INotifyCollectionChanged
액세스 할 수없는 경우 구현하는 컬렉션의 용도는 무엇입니까 CollectionChanged
?
답변:
해결책은 다음과 같습니다 . ReadOnlyObservableCollection의 CollectionChanged 이벤트
컬렉션을 INotifyCollectionChanged 로 캐스팅 해야합니다 .
이 작업을 수행하는 방법을 찾았습니다.
ObservableCollection<string> obsCollection = new ObservableCollection<string>();
INotifyCollectionChanged collection = new ReadOnlyObservableCollection<string>(obsCollection);
collection.CollectionChanged += new NotifyCollectionChangedEventHandler(collection_CollectionChanged);
INotifyCollectionChanged 인터페이스에서 명시 적으로 컬렉션을 참조하면 됩니다.
ReadOnlyObservableCollection
당신은이를 찾을 것입니다 event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged
. 이벤트의 명시 적 인터페이스 구현.
이 게시물은 오래되었지만 사람들은 주석을 달기 전에 .NET에서 사용되는 패턴을 이해하는 데 시간을 투자해야합니다. 읽기 전용 컬렉션은 소비자가 직접 수정하지 못하도록하는 기존 컬렉션의 래퍼입니다. 살펴보면 변경 가능할 수도 있고 불가능할 수도 ReadOnlyCollection
있는 래퍼임을 알 IList<T>
수 있습니다. 불변 컬렉션은 다른 문제이며 새로운 불변 컬렉션 라이브러리 에서 다룹니다.
즉, 읽기 전용은 불변과 동일하지 않습니다 !!!!
제쳐두고 ReadOnlyObservableCollection
암시 적으로 구현해야합니다 INotifyCollectionChanged
.
ReadOnlyObservableCollection 에 대한 컬렉션 변경 알림을 구독하려는 데에는 확실히 좋은 이유가 있습니다 . 따라서 단순히 컬렉션을 INotifyCollectionChanged 로 캐스팅하는 대신 ReadOnlyObservableCollection을 서브 클래 싱 하는 경우 다음은 CollectionChanged 이벤트 에 액세스하는보다 구문 상 편리한 방법을 제공합니다 .
public class ReadOnlyObservableCollectionWithCollectionChangeNotifications<T> : ReadOnlyObservableCollection<T>
{
public ReadOnlyObservableCollectionWithCollectionChangeNotifications(ObservableCollection<T> list)
: base(list)
{
}
event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged2
{
add { CollectionChanged += value; }
remove { CollectionChanged -= value; }
}
}
이것은 이전에 잘 작동했습니다.
이 문제를 설명하는 Microsoft Connect의 버그 항목에 투표 할 수 있습니다 : https://connect.microsoft.com/VisualStudio/feedback/details/641395/readonlyobservablecollection-t-collectionchanged-event-should-be-public
최신 정보:
Connect 포털은 Microsoft에 의해 종료되었습니다. 따라서 위의 링크는 더 이상 작동하지 않습니다.
My Win Application Framework (WAF) 라이브러리는 다음과 같은 솔루션을 제공합니다. ReadOnlyObservableList 클래스 :
public class ReadOnlyObservableList<T>
: ReadOnlyObservableCollection<T>, IReadOnlyObservableList<T>
{
public ReadOnlyObservableList(ObservableCollection<T> list)
: base(list)
{
}
public new event NotifyCollectionChangedEventHandler CollectionChanged
{
add { base.CollectionChanged += value; }
remove { base.CollectionChanged -= value; }
}
public new event PropertyChangedEventHandler PropertyChanged
{
add { base.PropertyChanged += value; }
remove { base.PropertyChanged -= value; }
}
}
이미 대답했듯이 두 가지 옵션이 있습니다. 명시 적으로 구현 된 이벤트 에 액세스 ReadOnlyObservableCollection<T>
하기 위해 인터페이스 INotifyCollectionChanged
로 캐스트 CollectionChanged
하거나 생성자에서 한 번 수행하고 래핑 된 이벤트를 연결하는 자체 래퍼 클래스를 만들 수 있습니다.ReadOnlyObservableCollection<T>
.
이 문제가 아직 수정되지 않은 이유에 대한 추가 정보 :
당신은에서 볼 수 있듯이 , 소스 코드 , ReadOnlyObservableCollection<T>
이벤트가 표시됩니다 공개, 밀봉되지 않은 (즉, 상속) 클래스이다 protected virtual
.
즉, ReadOnlyObservableCollection<T>
재정의 된 이벤트 정의는 있지만 protected
가시성을 갖는 에서 파생 된 클래스가있는 컴파일 된 프로그램이있을 수 있습니다 . 이벤트의 가시성이 다음과 같이 변경되면 해당 프로그램에 잘못된 코드가 포함됩니다.public
파생 클래스에서 이벤트의 가시성을 제한 할 수 없기 때문에 기본 클래스에서 .
그래서 안타깝게도 나중에 protected virtual
이벤트를 만드는 public
것은 바이너리 브레이킹 변경이므로 아주 좋은 추론 없이는 수행되지 않을 것입니다. "핸들러를 연결하려면 객체를 한 번 캐스팅해야합니다"는 그렇지 않습니다.
이것은 Google에서 최고 인기를 얻었으므로 다른 사람들이 이것을 찾을 경우에 대비하여 솔루션을 추가 할 것이라고 생각했습니다.
위의 정보 ( INotifyCollectionChanged 로 캐스트해야 함 )를 사용하여 등록 및 등록 취소를위한 두 가지 확장 메서드를 만들었습니다.
내 솔루션 -확장 방법
public static void RegisterCollectionChanged(this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler)
{
collection.CollectionChanged += handler;
}
public static void UnregisterCollectionChanged(this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler)
{
collection.CollectionChanged -= handler;
}
예
IThing.cs
public interface IThing
{
string Name { get; }
ReadOnlyObservableCollection<int> Values { get; }
}
확장 방법 사용
public void AddThing(IThing thing)
{
//...
thing.Values.RegisterCollectionChanged(this.HandleThingCollectionChanged);
}
public void RemoveThing(IThing thing)
{
//...
thing.Values.UnregisterCollectionChanged(this.HandleThingCollectionChanged);
}
OP의 솔루션
public void AddThing(IThing thing)
{
//...
INotifyCollectionChanged thingCollection = thing.Values;
thingCollection.CollectionChanged += this.HandleThingCollectionChanged;
}
public void RemoveThing(IThing thing)
{
//...
INotifyCollectionChanged thingCollection = thing.Values;
thingCollection.CollectionChanged -= this.HandleThingCollectionChanged;
}
대안 2
public void AddThing(IThing thing)
{
//...
(thing.Values as INotifyCollectionChanged).CollectionChanged += this.HandleThingCollectionChanged;
}
public void RemoveThing(IThing thing)
{
//...
(thing.Values as INotifyCollectionChanged).CollectionChanged -= this.HandleThingCollectionChanged;
}
ReadOnlyObservableCollection.CollectionChanged
노출되지 않았으므로 (다른 답변에 설명 된 유효한 이유 때문에) 노출하는 자체 래퍼 클래스를 만들어 보겠습니다.
/// <summary>A wrapped <see cref="ReadOnlyObservableCollection{T}"/> that exposes the internal <see cref="CollectionChanged"/>"/>.</summary>
public class ObservableReadOnlyCollection<T> : ReadOnlyObservableCollection<T>
{
public new NotifyCollectionChangedEventHandler CollectionChanged;
public ObservableReadOnlyCollection(ObservableCollection<T> list) : base(list) { /* nada */ }
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs args) =>
CollectionChanged?.Invoke(this, args);
}
사람들은 왜 읽기 전용 컬렉션의 변경 사항을 관찰해야하는지 물었으므로 여러 유효한 상황 중 하나를 설명하겠습니다. 읽기 전용 컬렉션이 변경할 수있는 개인 내부 컬렉션을 래핑하는 경우
다음은 그러한 시나리오 중 하나입니다.
서비스 외부에서 내부 컬렉션에 항목을 추가 및 제거 할 수있는 서비스가 있다고 가정합니다. 이제 컬렉션의 값을 노출하고 싶지만 소비자가 컬렉션을 직접 조작하는 것을 원하지 않는다고 가정합니다. 그래서 내부 컬렉션을 ReadOnlyObservableCollection
.
내부 컬렉션을 내부 컬렉션으로 래핑하려면 의 생성자
ReadOnlyObservableCollection
에서 파생ObservableCollection
되어야합니다ReadOnlyObservableCollection
.
이제 내부 콜렉션이 변경 될 때 (따라서 노출 된 ReadOnlyObservableCollection
변경 사항 이있을 때) 서비스 소비자에게 알리려고한다고 가정하십시오 . 오히려 자신의 구현을 압연보다 그냥 노출 할 CollectionChanged
의를 ReadOnlyObservableCollection
. 소비자가의 구현에 대해 가정하도록 강요하는 대신 을이 사용자 정의로 ReadOnlyObservableCollection
바꾸기 만하면됩니다.ReadOnlyObservableCollection
ObservableReadOnlyCollection
완료됩니다.
은 자체적으로 ObservableReadOnlyCollection
숨겨 ReadOnlyObservableCollection.CollectionChanged
지며 모든 컬렉션 변경 이벤트를 연결된 이벤트 처리기에 전달합니다.