首页 > 解决方案 > 使用 Gong 拖放对 ICollectionView 中的 Observable 集合进行排序

问题描述

我目前正在尝试创建一个 WPF/C#/EF6 应用程序,该应用程序将模拟看板以跟踪具有目标完成日期的任务。我正在使用 Gong-WPF-Drag-Drop nuget 包来允许在泳道之间进行良好的拖放。

该计划的核心围绕 2 个模型,泳道和工作(以下课程的相关部分)。我使用数据库优先的方法来生成这些模型。当通过辅助方法检索 Swimlane 信息时,Jobs 集合由 Observable 集合填充。

泳道

public partial class Swimlane : BaseModel
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Swimlane()
        {
            this.Jobs = new HashSet<Job>();
        }

        private int _slId;
        public int SlId 
        { 
            get { return _slId; } 
            set { SetProperty(ref _slId, value); } 
        }

        private int _clientId;
        public int ClientId 
        { 
            get { return _clientId; } 
            set { SetProperty(ref _clientId, value); } 
        }

        private string _slName;
        public string SlName 
        { 
            get { return _slName; } 
            set { SetProperty(ref _slName, value); } 
        }

        private int _sortOrder;
        public int SortOrder 
        { 
            get { return _sortOrder; } 
            set { SetProperty(ref _sortOrder, value); } 
        }


        public virtual Client Client { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Job> Jobs { get; set; }
    }

工作

 public partial class Job : BaseModel
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Job()
        {
        }

        private int _jobId;
        public int JobId 
        { 
            get { return _jobId; } 
            set { SetProperty(ref _jobId, value); } 
        }

        private int _clientId;
        public int ClientId 
        { 
            get { return _clientId; } 
            set { SetProperty(ref _clientId, value); } 
        }

        private Nullable<int> _assignedSwimLane;
        public Nullable<int> AssignedSwimLane 
        { 
            get { return _assignedSwimLane; } 
            set { SetProperty(ref _assignedSwimLane, value); } 
        }

        private string _name;
        public string Name 
        { 
            get { return _name; } 
            set { SetProperty(ref _name, value); } 
        }

        private string _owner_Fn;
        public string Owner_Fn 
        { 
            get { return _owner_Fn; } 
            set { SetProperty(ref _owner_Fn, value); } 
        }

        private string _owner_Ln;
        public string Owner_Ln 
        { 
            get { return _owner_Ln; } 
            set { SetProperty(ref _owner_Ln, value); } 
        }

        private string _owner_Email;
        public string Owner_Email 
        { 
            get { return _owner_Email; } 
            set { SetProperty(ref _owner_Email, value); } 
        }

        private string _owner_Phone;
        public string Owner_Phone 
        { 
            get { return _owner_Phone; } 
            set { SetProperty(ref _owner_Phone, value); } 
        }

        private Nullable<System.DateTime> _scheduledIn;
        public Nullable<System.DateTime> ScheduledIn 
        { 
            get { return _scheduledIn; } 
            set { SetProperty(ref _scheduledIn, value); } 
        }

        private Nullable<System.DateTime> _actualIn;
        public Nullable<System.DateTime> ActualIn 
        { 
            get { return _actualIn; } 
            set { SetProperty(ref _actualIn, value); } 
        }

        private Nullable<System.DateTime> _scheduledCompletion;
        public Nullable<System.DateTime> ScheduledCompletion 
        { 
            get { return _scheduledCompletion; } 
            set { SetProperty(ref _scheduledCompletion, value); } 
        }

        private Nullable<System.DateTime> _actualCompletion;
        public Nullable<System.DateTime> ActualCompletion 
        { 
            get { return _actualCompletion; } 
            set { SetProperty(ref _actualCompletion, value); } 
        }

        private Nullable<System.DateTime> _scheduledDelivery;
        public Nullable<System.DateTime> ScheduledDelivery 
        { 
            get { return _scheduledDelivery; } 
            set { SetProperty(ref _scheduledDelivery, value); } 
        }

        private Nullable<System.DateTime> _actualDelivery;
        public Nullable<System.DateTime> ActualDelivery 
        { 
            get { return _actualDelivery; } 
            set { SetProperty(ref _actualDelivery, value); } 
        }

        private Nullable<int> _sortOrder;
        public Nullable<int> SortOrder 
        { 
            get { return _sortOrder; } 
            set { SetProperty(ref _sortOrder, value); } 
        }


    }

应用程序将使用在视图模型中创建的 ICollectionView 按其订单号对泳道进行排序。如果不破坏拖放功能,我无法实现的部分是将排序顺序/过滤器应用于每个通道内的作业。

泳道的视图模型检索和iCollectionView的创建

        private ObservableCollection<Swimlane> _boardColumns;
        public ObservableCollection<Swimlane> BoardColumns
        {
            get { return _boardColumns; }
            set { _boardColumns = value; NotifyPropertyChanged("BoardColumns"); }
        }

        private ICollectionView _swimlaneCollection;
        public ICollectionView SwimlaneCollection
        {
            get { return _swimlaneCollection; }
            set { _swimlaneCollection = value; NotifyPropertyChanged("SwimlaneCollection"); }
        }

        private async void InitializeVmAsync()
        {
            BoardColumns = await Utils.SwimlaneHelper.GetAllSwimlanes();
            SignalrDelegator = new Utils.Signalr.SignalrHubDelegator(this);
            BindingOperations.EnableCollectionSynchronization("BoardColumns", _boardColumnsLock);

            SwimlaneCollection = CollectionViewSource.GetDefaultView(BoardColumns);
            SwimlaneCollection.Filter = ViewFilter;
            SwimlaneCollection.SortDescriptions.Add(new SortDescription("SortOrder", ListSortDirection.Ascending));
        }

我已使用 XAML 方法为每个泳道的作业集创建 ICollectionView,并对其应用默认排序。但是,这会破坏 gong 包的拖放功能。它不再让我在泳道上拖放。

XAML

<ItemsControl ItemsSource="{Binding SwimlaneCollection}" >
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <VirtualizingStackPanel Orientation="Horizontal"/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="*" />
                                </Grid.RowDefinitions>

                                <materialDesign:ColorZone Grid.Row="0" Mode="PrimaryDark"   Padding="16"  CornerRadius="4" 
                                                       materialDesign:ShadowAssist.ShadowDepth="Depth3"  Margin="8">
                                    <Grid>
                                        <Grid.RowDefinitions>
                                            <RowDefinition />
                                            <RowDefinition />
                                        </Grid.RowDefinitions>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="*"  />
                                            <ColumnDefinition Width="Auto" />
                                        </Grid.ColumnDefinitions>
                                        <TextBlock Grid.Column="0" Grid.Row="0" VerticalAlignment="Center" Text="{Binding SlName}" 
                                               Style="{StaticResource MaterialDesignTitleTextBlock}" />
                                        <TextBlock Grid.Column="0" Grid.Row="1" VerticalAlignment="Center" 
                                                   Text="{Binding Jobs, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource HoursCountConverter}}"
                                               Style="{StaticResource MaterialDesignSubheadingTextBlock}"/>
                                        <TextBlock Grid.Column="1" Grid.Row="0" VerticalAlignment="Center" 
                                                   Text="{Binding Jobs.Count, UpdateSourceTrigger=PropertyChanged, StringFormat={}({0}) }"
                                               Style="{StaticResource MaterialDesignSubheadingTextBlock}"/>
                                    </Grid>
                                </materialDesign:ColorZone>

                                <ListView  VerticalContentAlignment="Top" 
                                          HorizontalContentAlignment="Stretch" 
                                          VirtualizingStackPanel.IsVirtualizing="True"
                                            ScrollViewer.CanContentScroll="True"
                                            Grid.Row="1"
                                            dd:DragDrop.IsDragSource="True"
                                            dd:DragDrop.IsDropTarget="True"
                                            dd:DragDrop.DropHandler="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DockPanel}}}"
                                            dd:DragDrop.UseDefaultEffectDataTemplate="True"
                                            dd:DragDrop.UseDefaultDragAdorner="True">
                                    <ListView.Resources>
                                        <CollectionViewSource x:Key="JobsCvs" Source="{Binding Jobs}">
                                            <CollectionViewSource.SortDescriptions>
                                                <scm:SortDescription PropertyName="SortOrder" Direction="Ascending"/>
                                            </CollectionViewSource.SortDescriptions>
                                        </CollectionViewSource>
                                    </ListView.Resources>
                                    <ListView.ItemsSource>
                                        <Binding Source="{StaticResource JobsCvs}"/>
                                    </ListView.ItemsSource>
                                    <ListView.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <VirtualizingStackPanel VerticalAlignment="Top" />
                                        </ItemsPanelTemplate>
                                    </ListView.ItemsPanel>
                                    <ItemsControl.ItemContainerStyle>
                                        <Style TargetType="ListBoxItem">
                                            <Setter Property="Padding" Value="0"/>
                                            <Setter Property="Margin" Value="0"/>
                                            <Setter Property="BorderThickness" Value="0"/>
                                        </Style>
                                    </ItemsControl.ItemContainerStyle>  
                                    <ListView.ItemTemplate >
                                        <DataTemplate >
                                            <views:Card/>
                                        </DataTemplate>
                                    </ListView.ItemTemplate>
                                    <ListView.Template>
                                        <ControlTemplate>
                                            <ScrollViewer Focusable="False" Width="190">
                                                <ItemsPresenter SnapsToDevicePixels="True" Margin="-5" />
                                            </ScrollViewer>
                                        </ControlTemplate>
                                    </ListView.Template>
                                </ListView>
                            </Grid>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                    <ItemsControl.Template>
                        <ControlTemplate TargetType="ItemsControl">
                            <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
                                <ItemsPresenter/>
                            </ScrollViewer>
                        </ControlTemplate>
                    </ItemsControl.Template>
                </ItemsControl>

如何更改我的方法以保留 ICollectionView 的排序和过滤选项,但仍启用泳道之间和泳道内的拖放?我无法找到很多信息来显示使用 ICollectionViews 在集合中操作集合。

标签: c#wpfxaml

解决方案


我通过不实现排序(因为我想要内部拖放)并在视图 CollectionChanged 事件上放置一个处理程序来处理这个问题。这使我能够为集合中的项目设置属性。


推荐阅读