Windows Phone Toolkit上下文菜单项在删除项目然后添加项目时绑定了错误的对象

Sti*_*gar 4 silverlight silverlight-toolkit windows-phone

我刚刚遇到上下文菜单的一个严重问题,我几个小时都无法解决.

为了重现这个问题,我在Visual Studio 2012中使用Windows Phone 8的应用程序模板创建了一个全新的Panorama应用程序.我通过nugget安装了Windows Phone工具包,并在绑定到Items的第一个长列表选择器的数据模板中添加了上下文菜单

<StackPanel Margin="0,-6,0,12">
    <TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}" FontSize="{StaticResource PhoneFontSizeExtraLarge}"/>
    <toolkit:ContextMenuService.ContextMenu>
        <toolkit:ContextMenu>
            <toolkit:MenuItem Header="{Binding LineOne}" Click="MenuItem_Click_1" Tag="{Binding}">
            </toolkit:MenuItem>
        </toolkit:ContextMenu>
    </toolkit:ContextMenuService.ContextMenu>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)

我将标题设置为LineOne属性以便于调试.我附上了以下事件:

private void MenuItem_Click_1(object sender, RoutedEventArgs e)
{
    var itemViewModel = (ItemViewModel)((MenuItem)sender).Tag;
    App.ViewModel.Items.Remove(itemViewModel);
    App.ViewModel.Items.Add(new ItemViewModel { LineOne = "Test", LineTwo = "Test", LineThree = "Test" });
}
Run Code Online (Sandbox Code Playgroud)

我运行应用程序并使用上下文菜单删除第一个项目.第一个项目消失,名为Test的新项目按预期显示在列表底部.如果我持有这个新项目,则菜单项被绑定到"runtime one"(已删除的项目).

这是我可以重现错误的最简单的代码,但在我的真实应用程序中,我有相同的问题,更有意义的代码用于在不同的方法甚至不同的页面中添加和删除.我有一个命令绑定,但由于数据绑定错误,命令在错误的视图模型中使用错误的参数运行.

知道为什么会这样吗?

gho*_*ord 9

对于像我这样不想重新编译工具包的人来说,这是一个基于pantaloons回答的简单解决方法.Simpy添加Opened事件处理程序:

<toolkit:ContextMenu Opened="ContextMenu_Opened">
...
</toolkit:ContextMenu>
Run Code Online (Sandbox Code Playgroud)

事件处理程序代码:

private void ContextMenu_Opened(object sender, RoutedEventArgs e)
{
    var menu = (ContextMenu)sender;
    var owner = (FrameworkElement)menu.Owner;
    if (owner.DataContext != menu.DataContext)
        menu.DataContext = owner.DataContext;

}
Run Code Online (Sandbox Code Playgroud)


小智 5

LongListSelector是一个虚拟化控件,这意味着它实例化你指定固定次数的DataTemplate(我认为是20),然后在向下滚动列表时重用这些Item容器,只需移动它们并重新绑定它们的DataContext即可.这样,您可以拥有非常大的列表,而无需将所有内容放在Visual Tree中.

ContextMenu代码位于http://phone.codeplex.com/SourceControl/changeset/view/80797#1335947,OpenPopup()函数中包含以下行;

if (ReadLocalValue(DataContextProperty) == DependencyProperty.UnsetValue)
{
    DependencyObject dataContextSource = Owner ?? _rootVisual;
    SetBinding(DataContextProperty, new Binding("DataContext") { Source = dataContextSource });
}
Run Code Online (Sandbox Code Playgroud)

你会发现这里有一个错误,因为当虚拟化容器重新绑定DataContext时,它不会在_rootVisual上更新,因为它假定现有的DataContext是正确的.修复方法是将检查更改为:

if (ReadLocalValue(DataContextProperty) == DependencyProperty.UnsetValue ||
    (DataContext != dataContextSource.DataContext))
{
    DependencyObject dataContextSource = Owner ?? _rootVisual;
    SetBinding(DataContextProperty, new Binding("DataContext") { Source = dataContextSource });
}
Run Code Online (Sandbox Code Playgroud)