【问题标题】:How to unselect selected row in LongListSelector in WP8如何在 WP8 中取消选择 LongListSelector 中的选定行
【发布时间】:2014-02-20 00:42:37
【问题描述】:

我必须说我真的不喜欢 WP8 中的 LongListSelector 并且更喜欢工具包版本。

首先它不兼容 MVVM,所以我找到了这段代码来做到这一点。

  public class LongListSelector : Microsoft.Phone.Controls.LongListSelector
    {
        public LongListSelector()
        {
            SelectionChanged += LongListSelector_SelectionChanged;
        }

        void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            SelectedItem = base.SelectedItem;
        }

        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register(
                "SelectedItem",
                typeof(object),
                typeof(LongListSelector),
                new PropertyMetadata(null, OnSelectedItemChanged)
            );

        private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var selector = (LongListSelector)d;
            selector.SelectedItem = e.NewValue;
        }

        public new object SelectedItem
        {
            get { return GetValue(SelectedItemProperty); }
            set { SetValue(SelectedItemProperty, value); }
        }
    }

然后我使用 mvvm light 制作了一个视图模型

  public class MainViewModel : ViewModelBase
    {

        public MainViewModel()
        {
           MyList = new ObservableCollection<Test>
           {
               new Test
               {
                    Name = "test 1"
               },
               new Test
               {
                   Name = "test 2"
               }
           };

           ButtonCmd = new RelayCommand(() => Hit());
        }

        private void Hit()
        {
            SelectedItem = null;
        }

        public ObservableCollection<Test> MyList { get; set; }

        /// <summary>
        /// The <see cref="SelectedItem" /> property's name.
        /// </summary>
        public const string SelectedItemPropertyName = "SelectedItem";

        private Test selectedItem = null;

        /// <summary>
        /// Sets and gets the SelectedItem property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public Test SelectedItem
        {
            get
            {
                return selectedItem;
            }

            set
            {
                if (value != null)
                {
                    MessageBox.Show(value.Name);
                }


                if (selectedItem == value)
                {
                    return;
                }

                RaisePropertyChanging(() => SelectedItem);
                selectedItem = value;
                RaisePropertyChanged(() => SelectedItem);
            }
        }


        public RelayCommand ButtonCmd
        {
            get;
            private set;
        }

然后我做了一个模型

public class Test : ObservableObject
    {
        public string Name { get; set; }
    }

然后我制作了 xaml

<phone:PhoneApplicationPage
                            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                            xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
                            xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
                            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                            xmlns:ignore="http://www.ignore.com"
                            xmlns:local="clr-namespace:MvvmLight2" x:Class="MvvmLight2.MainPage"
                            mc:Ignorable="d ignore"
                            FontFamily="{StaticResource PhoneFontFamilyNormal}"
                            FontSize="{StaticResource PhoneFontSizeNormal}"
                            Foreground="{StaticResource PhoneForegroundBrush}"
                            SupportedOrientations="Portrait"
                            Orientation="Portrait"
                            shell:SystemTray.IsVisible="True"
                            DataContext="{Binding Main, Source={StaticResource Locator}}">

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot"
        Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <local:LongListSelector ItemsSource="{Binding MyList}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
            <local:LongListSelector.Resources>
                <DataTemplate x:Key="ItemTemplate">
                    <Grid>
                        <TextBlock Text="{Binding Name}" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="48"/>
                    </Grid>
                </DataTemplate>
            </local:LongListSelector.Resources>
            <local:LongListSelector.ItemTemplate>
                <StaticResource ResourceKey="ItemTemplate"/>
            </local:LongListSelector.ItemTemplate>
        </local:LongListSelector>
        <Button Content="Unselect" HorizontalAlignment="Left" Margin="142,81,0,0" Grid.Row="1" VerticalAlignment="Top" Command="{Binding ButtonCmd, Mode=OneWay}"/>
    </Grid>

</phone:PhoneApplicationPage>

当我单击列表中的第一项时,会显示消息框,如果我再次单击它,则没有任何反应。然后我点击我的按钮,将 selectedItem 清空(在旧的工具包版本中就足够了),然后再试一次,没有任何反应。

我每次选择第一行的唯一方法是选择第二行,如果说列表在任何给定时间只有一个项目,这真的很糟糕。

奇怪的是,一个简单的字符串集合甚至不需要我将 SelectItem 设置为 null,因为它似乎总是取消选择,但是当涉及到复杂类型时,这是不行的。

【问题讨论】:

  • 查看 ButtonCmd 的代码会很有用。不触发更改事件的唯一方法是没有感知到更改。
  • 所有代码都贴出来了,ButotnCmd会触发Hit()方法,只是设置SelectedItem为null;

标签: c# mvvm windows-phone-8 mvvm-light longlistselector


【解决方案1】:

我使用了相同的代码并遇到了同样的问题。原因是您的 SelectedItem 属性掩盖了 base.SelectedItem 属性。将其设置为新值时,不仅要设置 SelectedItem 属性,还要设置基本属性:

    public new object SelectedItem
    {
        get { return GetValue(SelectedItemProperty); }
        set 
        { 
            SetValue(SelectedItemProperty, value);
            base.SelectedItem = value;
        }
    }

然后你有一个支持 MVVM 的代码,并且可以在你的 ViewModel 中重置 SelectedItem(通过将其设置为 null)。

【讨论】:

    【解决方案2】:

    你可以通过在 selectionchanged 事件中轻松实现

    void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if((sender as LongListSelector).SelectedItem == null){
    
                 return;
                }
    
                SelectedItem = base.SelectedItem;
                (sender as LongListSelector).SelectedItem = null;   
            }
    

    【讨论】:

    • 嗯,这段代码破坏了应用程序。我认为这是因为当列表加载时没有选择任何内容,当我尝试选择某些内容时,空检查会阻止它被设置。
    • @chobo2 为什么要保存所选项目,您将在需要时获得该项目
    • @Romasz 在按照他的建议将其设为空之前我已经提出
    • @techlorr 没关系。我只是想告诉你我已经删除了 cmets(我会对这两个做同样的事情)——而不是就此进行聊天。所以你也可以删除你的。
    • 是的,我在选择时执行了一个操作(我转到另一个视图),这不是选择器抓住所选项目并对其进行处理的目的吗?通过您的代码检查,在我看来它基本上取出了 longlistselector 的选择点。
    猜你喜欢
    • 1970-01-01
    • 2012-12-02
    • 1970-01-01
    • 1970-01-01
    • 2014-09-07
    • 1970-01-01
    • 1970-01-01
    • 2016-12-30
    • 1970-01-01
    相关资源
    最近更新 更多