2014-02-22 2 views
0

전문가,ObservableCollection을 역순으로 정렬 하시겠습니까?

짧은 버전 :

방법의 ObservableCollection에의 종류의 끝에 가장 최근의, 그리고 내가 WPF 데이터 그리드에 표시하기 위해, 정확히 반대해야합니다. 지금은 모두 정상이지만 새 항목이 끝에 추가되므로 사용자는 추가 된 새 행을 볼 수 없습니다.

적은 짧은 버전 : 그들을 정렬 기준 /에,하지만 난 그냥 상단에 추가 할 수 있다면 솔직히 말해서, 내가 먹을수록 필요한 경우

나는, 엔트리 클래스에 날짜 시간 필드가 나는 심지어 을 필요로하지 않는다.! 난 그냥 필요

* 각 항목은 최고에 추가되는 컬렉션, 그리고 기본 바닥에 추가 *

조금 더 버전 :.

I 단순히 컬렉션의 '상단'에 새로운 요소를 도입하는 방법을 찾을 수 없습니다 ... "왜?" WPF 형식의 데이터 행을 표시하고 있으며 객체의 날짜 필드별로 정렬 된 가장 위쪽에 최신 정보를 표시하려고합니다.

IList와 동일하면 왜 그렇게 어려운가?

너무 복잡합니까? 저를 단순화하자

정말 긴 버전 : (가) 매우 시작하는 WPF 데이터 그리드의 행을 구성하는 클래스가에서

.

Public Class SysEvents 
    Inherits ObservableCollection(**Of Entry**) 

    Private Shared _list As New SysEvents 

    Public Sub New() 
    End Sub 
End Class 

ObservableCollection에가 비 있다 ...

Class Entry 
[...] 
Public Property TsCreated As Nullable(Of DateTime) 
Public Property EntryRaw As String 
    Set(value As String) 
     If value <> _entryRaw Then 
      _entryRaw = value 
      OnPropertychanged("EntryRaw") 
     End If 
    End Set 
    Get 
     Return _entryRaw 
    End Get 
End Property 
Private _entryRaw As String 
[...] 
End Class 

다음이 져야 할 엔트리의 ObservableCollection에있다 :이 클래스는 "엔트리"라고하며, 아래의 문제 만이 등록 정보는 재정의 함 하위 추가(), 내 쓸 수 없다. 자신의 하위 추가() 및 추가 후 오른쪽 정렬 ...

그래서이 WPF 창 클래스 (정말 간단하게 다시) 이렇게 있습니다 : 그것은 중요

Class MainWindow 

    Private RawEvents As New toag.syslog.SysEvents 

    Sub New() 
     grdEntryRaw.ItemsSource = RawEvents ' grid that holds rows 
    End Sub 

    Sub AddRow() 
     Me.RawEvents.Add(sysEvent) 
    End Sub 

End Class 

경우로, XAML (정렬 할 수 있나요 XAML에서?) :

<DataGrid x:Name="grdEntryRaw" [...]> 
    <DataGrid.Columns> 
     <DataGridTextColumn Binding="{Binding EntryRaw}" Header="Entry Raw" /> 
    </DataGrid.Columns> 
</DataGrid> 

확인을 클릭합니다. 아무도 그에게이 멀리 버전을하지 : 나는 .Add()를 바인딩이하고있는 것을 가로 챌 수 없기 때문에 내가 어떤 정렬 알고리즘으로도 얻을 수없는 것처럼

, 그것은 ... 보인다

나는이 많은 걸 알았을 때 싸움이 끝났다고 생각했다.하지만 이제는 1 야드 라인에서 성공을 거둔 것으로 보인다. 오, 비주얼 스튜디오 .. 우선은이 ...

TIA 잔인한 주부입니다!

+0

오히려 추가보다는, 당신은 삽입/InsertItem를 시도? 데이터/시간 기반이고 (실시간으로 가져 오거나 추가하는 경우) 처음에 삽입 (끝에)을 삽입하는 것이 아닙니다. – Plutonix

+0

NotifyCollectionChangedEventArgs 이벤트에 액세스했지만 컬렉션의 COPY 만 처리 중이므로 ByRef를 수행 할 수 없습니다. Public Sub CollChanged (보낸 사람 개체, e As System.Collections.Specialized.NotifyCollectionChangedEventArgs) 처리 Me.CollectionChanged 괜찮 았지만 여전히 사본을 다루고 있습니다 ... : ( SortedList.Move (Me.iTotalElements, 0) –

+0

@Plutonix, 바인딩 및/또는 콜렉션 호출 Add() 자동으로, 그리고 나는 그것을 가로 챌 수 없다. 위와 같이 이벤트를 사용하는 경우 컬렉션 (보낸 사람) 복사본을 혼란에만 ... :(삽입 또는 다른 ObservableCollection 연산자를 사용하려면 _LOVE_ 줄 그건 도움이 될거야 ...하지만 어떻게? NOTE : 끝까지 추가하는 것은 지금하는 방식이고, 나는 그것을 바꿀 수는 없다. –

답변

1

INotifyCollectionChangedINotifyPropertyChanged을 구현하는 것 외에도 ObservableCollection에 대한 특별한 것은 없습니다.

는 당신이 필요한 행동 ObservableCollection 직접 만들 것을 제안합니다.

Public Class ObservableStack(Of T) 
    Implements IEnumerable, ICollection, IList 
    Implements IEnumerable(Of T), ICollection(Of T), IList(Of T) 
    Implements INotifyCollectionChanged, INotifyPropertyChanged 

    Public Sub New() 
     Me.list = New List(Of T) 
    End Sub 

    '... 

    Public Sub Add(item As T) Implements ICollection(Of T).Add 
     'TODO: Validate. 
     Me.list.Insert(0, item) 'Insert at top of the list. 
     Me.RaisePropertyChanged("Count") 
     Me.RaisePropertyChanged("Item") 
     Me.RaiseCollectionChanged(NotifyCollectionChangedAction.Add, item, 0) 
    End Sub 

    Private Function _Add(obj As Object) As Integer Implements IList.Add 
     Me.Add(TryCast(obj, T)) 
     Return 0 
    End Function 

    '... 

    Private ReadOnly list As List(Of T) 

End Class 

예 비요른 - 로저 Kringsjå @

Public Class ObservableStack(Of T) 
    Implements IEnumerable, ICollection, IList 
    Implements IEnumerable(Of T), ICollection(Of T), IList(Of T) 
    Implements INotifyCollectionChanged, INotifyPropertyChanged 

    Public Sub New() 
     Me.list = New List(Of T) 
    End Sub 

    Public Event CollectionChanged As NotifyCollectionChangedEventHandler Implements INotifyCollectionChanged.CollectionChanged 
    Protected Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged 

    Public ReadOnly Property Count() As Integer Implements ICollection.Count, ICollection(Of T).Count 
     Get 
      Return Me.list.Count 
     End Get 
    End Property 

    Default Public Property Item(index As Integer) As T Implements IList(Of T).Item 
     Get 
      Return Me.list.Item(index) 
     End Get 
     Set(value As T) 
      Me.Replace(index, value) 
     End Set 
    End Property 

    Private ReadOnly Property _IsFixedSize() As Boolean Implements IList.IsFixedSize 
     Get 
      Return CType(Me.list, IList).IsFixedSize 
     End Get 
    End Property 

    Private ReadOnly Property _IsReadOnly() As Boolean Implements IList.IsReadOnly, ICollection(Of T).IsReadOnly 
     Get 
      Return CType(Me.list, IList).IsReadOnly 
     End Get 
    End Property 

    Private ReadOnly Property _IsSynchronized() As Boolean Implements ICollection.IsSynchronized 
     Get 
      Return CType(Me.list, ICollection).IsSynchronized 
     End Get 
    End Property 

    Private Property _Item(index As Integer) As Object Implements IList.Item 
     Get 
      Return Me.Item(index) 
     End Get 
     Set(value As Object) 
      Me.Item(index) = DirectCast(value, T) 
     End Set 
    End Property 

    Private ReadOnly Property _SyncRoot() As Object Implements ICollection.SyncRoot 
     Get 
      Return CType(Me.list, ICollection).SyncRoot 
     End Get 
    End Property 

    Public Sub Add(item As T) Implements ICollection(Of T).Add 
     Me.Insert(0, item) 
    End Sub 

    Public Sub Clear() Implements IList.Clear, ICollection(Of T).Clear 
     If (Me.Count > 0) Then 
      Me.list.Clear() 
      Me.RaisePropertyChanged("Count") 
      Me.RaisePropertyChanged("Item") 
      Me.RaiseCollectionReset() 
     End If 
    End Sub 

    Public Function Contains(item As T) As Boolean Implements ICollection(Of T).Contains 
     Return Me.list.Contains(item) 
    End Function 

    Public Sub CopyTo(array() As T, index As Integer) Implements ICollection(Of T).CopyTo 
     Me.list.CopyTo(array, index) 
    End Sub 

    Public Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator 
     Return Me.list.GetEnumerator() 
    End Function 

    Public Function IndexOf(item As T) As Integer Implements IList(Of T).IndexOf 
     Return Me.list.IndexOf(item) 
    End Function 

    Public Sub Insert(index As Integer, item As T) Implements IList(Of T).Insert 
     'TODO: Validate item. 
     Me.list.Insert(index, item) 
     Me.RaisePropertyChanged("Count") 
     Me.RaisePropertyChanged("Item") 
     Me.RaiseCollectionChanged(NotifyCollectionChangedAction.Add, item, index) 
    End Sub 

    Public Sub Move(ByVal oldIndex As Integer, ByVal newIndex As Integer) 
     Me.MoveItem(oldIndex, newIndex) 
    End Sub 

    Protected Overridable Sub MoveItem(ByVal oldIndex As Integer, ByVal newIndex As Integer) 
     Dim item As T = Me.Item(oldIndex) 
     Me.list.RemoveAt(oldIndex) 
     Me.list.Insert(newIndex, item) 
     Me.RaisePropertyChanged("Item") 
     Me.RaiseCollectionChanged(NotifyCollectionChangedAction.Move, item, newIndex, oldIndex) 
    End Sub 

    Protected Overridable Sub OnCollectionChanged(e As NotifyCollectionChangedEventArgs) 
     RaiseEvent CollectionChanged(Me, e) 
    End Sub 

    Protected Overridable Sub OnPropertyChanged(e As PropertyChangedEventArgs) 
     RaiseEvent PropertyChanged(Me, e) 
    End Sub 

    Private Sub RaiseCollectionChanged(action As NotifyCollectionChangedAction, item As T, index As Integer) 
     Me.OnCollectionChanged(New NotifyCollectionChangedEventArgs(action, item, index)) 
    End Sub 

    Private Sub RaiseCollectionChanged(ByVal action As NotifyCollectionChangedAction, ByVal item As Object, ByVal index As Integer, ByVal oldIndex As Integer) 
     Me.OnCollectionChanged(New NotifyCollectionChangedEventArgs(action, item, index, oldIndex)) 
    End Sub 

    Private Sub RaiseCollectionChanged(action As NotifyCollectionChangedAction, oldItem As T, newItem As T, index As Integer) 
     Me.OnCollectionChanged(New NotifyCollectionChangedEventArgs(action, newItem, oldItem, index)) 
    End Sub 

    Private Sub RaiseCollectionReset() 
     Me.OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)) 
    End Sub 

    Private Sub RaisePropertyChanged(propertyName As String) 
     Me.OnPropertyChanged(New PropertyChangedEventArgs(propertyName)) 
    End Sub 

    Public Function Remove(item As T) As Boolean Implements ICollection(Of T).Remove 
     Dim index As Integer = Me.IndexOf(item) 
     If (index <> -1) Then 
      Me.RemoveAt(index) 
      Return True 
     End If 
     Return False 
    End Function 

    Public Sub RemoveAt(index As Integer) Implements IList.RemoveAt, IList(Of T).RemoveAt 
     Dim item As T = Me.Item(index) 
     Me.list.RemoveAt(index) 
     Me.RaisePropertyChanged("Count") 
     Me.RaisePropertyChanged("Item") 
     Me.RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, item, index) 
    End Sub 

    Public Sub Replace(index As Integer, newItem As T) 
     'TODO: Validate item. 
     Dim oldItem As T = Me.Item(index) 
     Me.list.Item(index) = newItem 
     Me.RaisePropertyChanged("Item") 
     Me.RaiseCollectionChanged(NotifyCollectionChangedAction.Replace, oldItem, newItem, index) 
    End Sub 

    Private Function _Add(obj As Object) As Integer Implements IList.Add 
     Me.Add(DirectCast(obj, T)) 
     Return 0 
    End Function 

    Private Function _Contains(obj As Object) As Boolean Implements IList.Contains 
     Return Me.Contains(DirectCast(obj, T)) 
    End Function 

    Private Sub _CopyTo(array As Array, index As Integer) Implements ICollection.CopyTo 
     CType(Me.list, ICollection).CopyTo(array, index) 
    End Sub 

    Private Function _GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator 
     Return Me.GetEnumerator() 
    End Function 

    Private Function _IndexOf(obj As Object) As Integer Implements IList.IndexOf 
     Return Me.IndexOf(DirectCast(obj, T)) 
    End Function 

    Private Sub _Insert(index As Integer, obj As Object) Implements IList.Insert 
     Me.Insert(index, DirectCast(obj, T)) 
    End Sub 

    Private Sub _Remove(obj As Object) Implements IList.Remove 
     Me.Remove(DirectCast(obj, T)) 
    End Sub 

    Private ReadOnly list As List(Of T) 

End Class 
+0

나는 이것을 시도하고있다. 그러나 비표준 클래스를위한 구현 된 인터페이스는 상충되는 메소드와 서브 이름을 가진 것처럼 보인다. 나는 8에서 위의 목록을 다듬을 필요가있다. .. 지금 어느 것을 지어야하는지에 관해 계산하려고 노력한다! :) –

+0

@PatTrainor 당신이 일하는 해결책을 찾은 것을 기쁘게 생각합니다. _my solution_에 관하여 : 먼저 IEnumerable, ICollection, IList를 순서대로 구현합니다. 거의 모든 필드는 private이어야하며'Private Function _Add (Object as obj As Object) As Integer Implements IList.Add'와 같은 밑줄을 사용하여 이름을 지정할 수 있습니다. 이제'Count'와'RemoveAt' 같은 몇몇 필드는'Public ReadOnly Property Count()와 같은 다른 인터페이스에 의해 public과 "shared"되어야합니다. Integer는 ICollection.Count, ICollection (Of T) .Count'를 구현합니다. 예제를 추가했습니다. 내 편집을 참조하십시오. –

0

은 확실히 올바른 방향으로 절 지적했다.

나는 최소한까지 일을 제거. WPF MainWindow를 클래스의 상단에

선언 : 대신 내 자신의 컬렉션 클래스를 만드는

, 내가 WPF 창 클래스의 내부 컬렉션을 만든 다음

Private RawEvents As ObservableCollection(Of Entry) 

, 나는 그것을 인스턴스화했다 클래스 '인스턴스의 역학 및의 데이터 그리드에 대한 발발했습니다 ItemsSource를 SE는 : 왼쪽

RawEvents = New ObservableCollection(Of Entry) 
grdEntryRaw.ItemsSource = RawEvents ' source for main window (events) 

유일한 것은 폐기물 수집에 새로운 이벤트를 넣어했다 메시지 대기열에서 새로운 이벤트가 발생하지만 중요하지는 않습니다 :

Public Sub PeekQ(ByVal sender As System.Object, ByVal e As System.Messaging.PeekCompletedEventArgs) Handles Q.PeekCompleted 
    [..]  
    ' send to main display (newest entries on top) 
    Me.Dispatcher.Invoke(CType(Sub() **Me.RawEvents.Insert(0, someEvent)**, Action)) 
    ' 
    Me.CountryLookupQ.BeginPeek() 

End Sub 

... 그게 전부입니다! 이벤트를 개최하기 위해 추가 클래스가 필요하지 않았습니다 ... WPF 창 내부에서 생성 된 ObservableCollection을 사용했습니다. XAML 죽은 간단하고, 가장 중요한 부분은 어떤 정렬 알고리즘이 없다는 것입니다 :

[...] 
<DockPanel x:Name="EntryRawDockPanel" HorizontalAlignment="Left" LastChildFill="False" Width="517" Margin="0,26,0,41"> 
    <DataGrid x:Name="grdEntryRaw" Grid.Column="1" Margin="0,0,10,43" AutoGenerateColumns="False" HorizontalContentAlignment="Stretch" CanUserAddRows="False" CanUserDeleteRows="True" AlternatingRowBackground="#FFDEFFE4"> 
     <DataGrid.Columns> 
      <DataGridTextColumn Binding="{Binding EntryRaw}" Header="Entry Raw" IsReadOnly="False"/> 
     </DataGrid.Columns> 
    </DataGrid> 
</DockPanel> 
[...] 

솔직히, 즉 전체 솔루션입니다. Entry() 클래스는 어떤 식 으로든 특별하지 않습니다.

다른 사람들에게 도움이 되었으면합니다. 예, XAML에서 정렬하고 XAML에서 클래스를 인스턴스화하는 것과 같은 여러 가지 방법을 보았습니다. 그러나이 방법은 작성 방법 중 가장 쉬운 방법입니다.

관련 문제