以下是最基本的问题:如何监听通过DragDropTarget修改的TreeView控件中更改内容的更新?
所以这是我的交易:我有一个持有议程项目的TreeView。所有都具有相同的数据类型(WCFAgendaItem),并加载到层次结构中,子项表示为属性ChildItems。整个事情都包含在一个ObservableCollection中,并使用MVVM Light绑定到TreeView。非常适合查看。我还希望用户能够使用拖放来重新排序,重新组织和添加来自各种其他来源的新议程(一个示例是图像幻灯片的ListView)。为了保持一致性和易于序列化,所有新项目也将具有相同的WCFAgendaItem数据类型。
这是我的问题:使用Toolkit的拖放功能在UI上进行精美的拖放工作。但我不知道如何让ViewModel理解对TreeView内容的更改。
视图中的代码(Agenda.xaml):
(在上面)
<UserControl.Resources>
<AHHSTeam_SLClassroomManagerMVVM_Helpers_Converters:BooleanVisibilityConverter x:Key="BooleanVisibilityConverter"/>
<sdk:HierarchicalDataTemplate x:Key="hdtAgenda" ItemsSource="{Binding ChildItems, Mode=TwoWay}" >
<Grid HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding ImageThumbnailWidth}" />
<ColumnDefinition Width="250" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding ThumbnailURL}" Width="{Binding ImageThumbnailWidth}" Height="{Binding ImageThumbnailHeight}" Visibility="{Binding HasImage, Converter={StaticResource BooleanVisibilityConverter}}" >
<ToolTipService.ToolTip>
<Image Source="{Binding ResizedImageURL}" />
</ToolTipService.ToolTip>
</Image>
<TextBlock Grid.Column="1" Text="{Binding Title}" TextWrapping="Wrap" />
</Grid>
</sdk:HierarchicalDataTemplate>
<Style TargetType="sdk:TreeViewItem" >
<Setter Property="IsExpanded" Value="True" />
</Style>
</UserControl.Resources>
(稍后)
<controlsToolkit:TreeViewDragDropTarget Grid.Row="1" Grid.Column="0" x:Name="ddtAgenda" AllowDrop="True"
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" >
<sdk:TreeView Width="375" ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Visible" ItemsSource="{Binding DailyAgenda, Mode=TwoWay}" ItemTemplate="{StaticResource hdtAgenda}">
</sdk:TreeView>
</controlsToolkit:TreeViewDragDropTarget>
ViewModel代码(AgendaViewModel.cs) - &gt;我试着收听CollectionChanged,到目前为止似乎没有用
(在构造函数中)
//add notification of agenda changes
DailyAgenda.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(DailyAgenda_CollectionChanged);
(事件)
void DailyAgenda_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
System.Windows.MessageBox.Show("Daily agenda updated, now has " + e.NewItems.Count.ToString() + " top-level elements.");
}
模型代码(WCFAgendaItem.cs)
[ContentProperty("ChildItems")]
public partial class WCFAgendaItem: INotifyPropertyChanged
{
private ObservableCollection<WCFAgendaItem> _childItems = new ObservableCollection<WCFAgendaItem>();
public ObservableCollection<WCFAgendaItem> ChildItems
{
get
{
return _childItems;
}
set
{
_childItems = value;
}
}
...
我很确定我听说CollectionChanged在任何情况下都是不对的,因为这些数据不仅仅是在顶层更改。我查看了Blend中的EventToCommand(MVVM Light,请记住),但唯一的TreeView特定事件似乎是SelectionChanged,这似乎也不正确。我看了在TreeViewDragDropTarget上放置一个EventToCommand触发器,但是不是那些覆盖UI交互发生方式的方法吗?我不认为WCFAgendaItem上的INotifyPropertyChanged也适合这个:虽然我以后想要编辑项目标题,但是当项目移动时它似乎不会帮助我。
也许我正在寻找的是一个延伸,但我真正希望发生的是Silverlight了解数据绑定在WCFAgendaItem集合的排序和内容两方面都有效,并且完成所有集合的重新处理基于UI交互。然后我可以在重新设计集合之后监听更新事件 - 之后我可以抓取绑定到TreeView的修改后的ObservableCollection,并通过WCF展平/序列化/更新。
失败理想情况:如果需要,我愿意抓取TreeViewItems,但即使这是我需要做的事情,我仍然坚持要做什么。另外,我需要一种方法将所有这些传递回ViewModel,因此我不会编写代码。我是否需要附加到Drop()并重写掉线逻辑?我从Toolkit开始发现了一些关于自定义拖放实现的旧文章,但没有人提到如何保存修改后的TreeView,尤其是在MVVM情况下。
终于{
在输入时我发现this article可能有用,虽然这在ViewModel中是相当多的工作。这是有希望的,我会调查,但我仍然希望更简单的事情。此外,自撰写文章以来,工具包事件似乎发生了一些变化。
}
答案 0 :(得分:0)
我在实现这种类型的DragDrop功能时也遇到了问题。根本原因似乎是ItemDragCompleted事件(EventHandler)和ItemDroppedOnSource(DragEventHandler)都没有传递项目被删除的索引。
我最终继承了DragDropTarget,以便公开受保护的方法:
int GetDropTargetInsertionIndex(TItemsControlType dropTarget, DragEventArgs args)
然后,我使用附加行为来承担将指定索引处的项插入到基础集合的责任。
我担心底层代码太过庞大而无法包含在StackOverflow答案中(主要是由于广泛的解耦),但它在我的博客主题列表中。与此同时,我希望上面的信息有所帮助,这对我来说无疑是解决方案的关键。
伊恩