【问题标题】:Scrolling in CollectionView does not maintain Switch toggle selection在 CollectionView 中滚动不会保持 Switch 切换选择
【发布时间】:2020-04-29 09:30:55
【问题描述】:

我有以下CollectionView -

<CollectionView x:Name="PCollection" ItemsSource="{Binding P.data}" Margin="0,10,2,10">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <StackLayout>
                <Image Source="p" HeightRequest="60" WidthRequest="60" />
                <StackLayout Orientation="Vertical" >
                    <Label Text="{Binding id}" VerticalOptions="Center" IsVisible="False"/>
                    <StackLayout Orientation="Horizontal" >+
                    <Switch IsToggled="{Binding IsOwned, Mode=TwoWay}" HorizontalOptions="Start" Toggled="Switch_Toggled_Place" />
                </StackLayout>
            </StackLayout>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

我的代码在后面 -

bool _isOwned;
public bool IsOwned
{
    get
    {
        return _isOwned;
    }
    set
    {
        _isOwned = value;

    }
}

private void Switch_Toggled_Place(object sender, ToggledEventArgs e)
{

}

我的问题是,当我切换集合中的开关时,一切都按预期工作,我进入Switch_Toggled_Place。然而,假设集合中有 20 个项目,当我向上滚动并且切换开关消失时,由于某种原因它会再次触发 Switch_Toggled_Place 并取消选中我的开关!

我尝试从绑定中删除Mode=TwoWay,但没有效果。我还尝试确定切换事件是来自用户输入还是来自代码本身触发但再次无效。我该如何解决这个问题,我相信这很简单。

【问题讨论】:

    标签: c# xaml xamarin.forms collectionview


    【解决方案1】:

    根据这个GitHub Issue,这是一个向开关添加OnClick事件的建议,人们遇到了同样的问题。

    话虽如此,作为一种解决方法,您可以使用 TapGesture 在开关顶部添加一个 StackLayout 来注册点击,然后切换/取消切换开关,从而无需切换事件

    例如:

    <Grid>
        <Switch IsToggled="{Binding IsOwned}"></Switch>
        <StackLayout>
            <StackLayout.GestureRecognizers>
                <TapGestureRecognizer 
                    Tapped="OnSwitchTapped" 
                    NumberOfTapsRequired="1">
            </StackLayout.GestureRecognizers>
        </StackLayout>
    </Grid>
    
    ...
    
    public void OnSwitchTapped(object sender, EventArgs e)
    {
        //Change Switch IsToggle
        //add code here
    }
    

    这是一个非常简单的示例,但您知道需要做什么。这绝不是一个好的解决方案,它是一种解决方法,你的做法是正确的

    【讨论】:

    • 我会尽快尝试并报告!
    • @Ebikeneser 还看看 Lucas 的回答,我假设您的事件在没有用户交互的情况下触发,并且 Switch_Toggled_Place 触发了一些您不想要的代码,而不是因为您的绑定不正确,无论哪种方式如果你没有成功,你总是有这个解决方案
    • 简单有效。我有一个 CollectionView,其中 SwipeView 作为 DataTemplate 和一个切换作为 Swipe 中的视图元素之一。滚动集合时,至少在 Android 上,使用 Xamarin.Forms v5 prerelease 2 反复触发 Toggled 事件。解决该错误的方法与 toggled 完成相同的任务。
    【解决方案2】:

    需要实现接口INotifyPropertyChanged

    在您的模型中

    public partial class MyModel: INotifyPropertyChanged
    {
       public event PropertyChangedEventHandler PropertyChanged;
    
        void OnPropertyChanged([CallerMemberName] string name = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    
       bool _isOwned;
       public bool IsOwned
       { 
         get
         {
            return _isOwned;
         }
         set
         {
            if(_isOwned!=value)
                {
                    _isOwned= value;
                    OnPropertyChanged(nameof(IsOwned));
    
                }
    
          }
    }
    
    
    

    而且由于您使用过 MVVM ,因此您应该在 ViewModel 而不是 Event 中处理逻辑。否则会和数据绑定冲突。

    在你的 ViewMNodel 中

    public class MyViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        void OnPropertyChanged([CallerMemberName] string name = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    
        // MySource here is the ItemsSource of CollectionView
        public ObservableCollection<MyModel> MySource { get; set; }
    
    
        public MyViewModel()
        {
            MySource = new ObservableCollection<MyModel>() {
    
           //...
            };
    
            foreach(MyModel model in MySource)
            {
                model.PropertyChanged += Model_PropertyChanged;
            }
    
        }
    
        private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if(e.PropertyName== "IsOwned")
            {
              // do some thing you want here .
            }
        }
    }
    

    【讨论】:

    • 我发现我没有使用正确的设计模式,我会实施并报告。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-29
    • 1970-01-01
    相关资源
    最近更新 更多