在Windows Phone 8.1中,将ListView的SelectedItems绑定到ViewModel

4
我有以下代码:

<ListView SelectionMode="Multiple" ItemsSource="{Binding MyList}" ItemTemplate="{StaticResource MyListTemplate}">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
        </Style>
    </ListView.ItemContainerStyle>
</ListView>

使用以下DataTemplate:
<Page.Resources>
    <!-- Data Template for the ListView -->
    <DataTemplate x:Key="MyListTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="150" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Image Grid.Column="0" Source="{Binding Path=Icon}" />
            <StackPanel Grid.Column="1" Orientation="Vertical">
                    <TextBlock Text="{Binding Path=EntryDate}" TextAlignment="Left" />
                <TextBlock Text="{Binding Path=Url}" TextAlignment="Left" />
                <TextBlock Text="{Binding Path=Text}" TextAlignment="Left" />
            </StackPanel>
        </Grid>
    </DataTemplate>
</Page.Resources>

在我的ViewModel中,我有以下内容:
private ObservableCollection<MyModel> myList;
public ObservableCollection<MyModel> MyList {
    get { return myList; }
    set {
        myList = value;
        RaisePropertyChanged("MyList");
    }
}

public IEnumerable<MyModel> SelectedItems {
    get { return MyList == null ? null : MyList.Where(e => e.IsSelected); }
}

在我的模型中,除了其他属性之外,我还有一个IsSelected属性:

private bool isSelected;
public bool IsSelected {
    get { return isSelected; }
    set { Set(ref isSelected, value); }
}

我可以看到SelectedItems包含了MyList的所有元素,但是当我在UI中选择一些元素时,IsSelected属性没有更新,它们仍然都是false。
那么我在这里做错了什么?

你能展示一下 MyListTemplate 吗? - Flat Eric
问题已经更新了DataTemplate。 - Schrödinger's Box
你是否在IsSelected的setter上设置了断点,以检查当你点击一个项目时它是否被调用? - Flat Eric
奇怪,我刚在WPF上测试过它,它可以工作。无法在WP8.1上测试,因为我没有它。 - Flat Eric
ListView。我完全复制了你的代码(除了方法Set(ref isSelected, value))。 - Flat Eric
显示剩余6条评论
1个回答

5

感谢MSDN论坛中的YossiStarz,我成功解决了我的问题。以下是他的解决方案:

问题在于您不能使用Style来对放置了该样式的元素进行SetBinding操作。这是因为当ListView创建时,样式只会被创建一次,而不是为每个项目容器都创建一次。实际上,您创建了一个样式对象,其中包含一个Setter对象,其Value属性绑定到样式父DataContext的IsSelected(它不存在)。此绑定发生以设置Setter中Value属性的值。如果它成功获取到值,这将是它将要设置给所有项目容器的值。
我为您提供了一个解决方案。
首先,最简单的方法是创建这个帮助类:

public class Helper {
    public static string GetIsSelectedContainerBinding(DependencyObject obj) {
        return (string)obj.GetValue(IsSelectedContainerBindingProperty);
    }

    public static void SetIsSelectedContainerBinding(DependencyObject obj, string value) {
        obj.SetValue(IsSelectedContainerBindingProperty, value);
    }

    // Using a DependencyProperty as the backing store for IsSelectedContainerBinding.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsSelectedContainerBindingProperty =
        DependencyProperty.RegisterAttached("IsSelectedContainerBinding", typeof(string), typeof(helper), new PropertyMetadata(null, IsSelectedContainerBindingPropertyChangedCallback));

    public static void IsSelectedContainerBindingPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) {
        BindingOperations.SetBinding(d, ListViewItem.IsSelectedProperty, new Binding() {
            Source = d,
            Path = new PropertyPath("Content." + e.NewValue),
            Mode = BindingMode.TwoWay
        });
    }
}

现在将setter更改为以下内容:
<Style TargetType="ListViewItem">
    <Setter Property="local:Helper.IsSelectedContainerBinding" Value="IsSelected"/>
</Style>

这应该将SetBinding应用于每个创建的容器。


1
仅供参考,类似的问题在这里被问到了 - 在Setters中没有绑定,是的。https://dev59.com/W2ct5IYBdhLWcg3wvf7J - Igor Ralic
感谢您提供的参考,我想在当时(2012年)可用的版本中可能不允许这样做。 - Schrödinger's Box
谢谢。我也有同样的解决方案,差点放弃了。关键是在“Content.”前缀。再次感谢!!! - Thomas
通用 Windows 应用程序是否支持在 Setter 中使用绑定? - SuperJMN
1
@SuperJMN 我不认为它们是原生支持的,至少不是这样:http://stackoverflow.com/questions/22518133/error-when-trying-to-bind-the-value-of-a-setter - Schrödinger's Box

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接