【问题标题】:Focus ViewCell Entry on ListView item selection将 ViewCell 条目聚焦在 ListView 项目选择上
【发布时间】:2018-07-26 10:29:22
【问题描述】:

我有一个带有自定义 ViewCell 的 Xamarin.Forms ListView,其中包含一个带有条目和标签的 StackLayout。我希望在任何时候选择 ViewCell 时条目都能获得焦点。

ItemSelected 提供被选中的项目,但不提供 ViewCell。我可以为 ViewCell 创建一个自定义类,但我不知道它如何知道它何时被选中。

如何将条目集中在 ListView 项目选择上?

【问题讨论】:

  • 您如何忽略选择并在 stacklayout 上处理 TapGesture,重定向操作以聚焦您的条目?
  • 选择可能不是通过点击产生的。例如,当添加一个新项目时,它会自动被选中,并且它的 Entry 应该会自动获得焦点。
  • 能否获取item的索引,然后根据索引手动抓取ViewCell?

标签: listview xamarin.forms


【解决方案1】:

我这样做的方法是创建一个类 - Viewholder - 包含您想要的 2 个视图。然后将其用于 ListView ItemSource,并专注于 SelectedItem 属性更改。

观看者:

public class Viewholder 
{
    public Viewholder (){
    }

    public void OnFocus(){
        Entry.Focus();
    }

    private Entry _entry ;   
    public Entry Entry{
        get { return _entry;}
        set{
            if (value != null && 
            _entry!= value){
            _entry= value;
            OnPropertyChanged();
        }
    }

    private Label _label    
    public Label Label{
        get { return _label;}
        set{
            if (value != null && 
            _label!= value) {
            _label= value;
            OnPropertyChanged();
        }
    }   

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string propertyName = null){
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

MainPage(ListView 父级):

public class MainPage : ContentPage
{
    public MainPage () {
        SetUpControls();
    }

    private ObservableCollection<ViewHolder> _viewHolders;
    public ObservableCollection<ViewHolder> ViewHolders
    {
        get { return _viewHolders;}
        set{
            if (value != null && 
            _viewHolders!= value){
            _viewHolders= value;
            OnPropertyChanged();
        }
    }

    private ViewHolder _selectedViewHolder;
    public ViewHolder SelectedViewHolder{
        get { return _selectedViewHolder;}
        set{
            if (value != null && 
                _selectedViewHolder != value){
                    _selectedViewHolder= value;
                    OnPropertyChanged();
                    _selectedViewHolder.OnFocus();
        }
    }

    private void SetUpControls(List<string> l){
        foreach(var s in l){
            ViewHolder v = new ViewHolder{
                Label = new Label{
                    Text = s,
                };    
                Entry = new Entry();
            };

            ViewHolders.Add(v);
        }

        if(l.Count > 0){
            SelectedViewHolder = ViewHolders.ElementAt(0);
        }
    }    
}

XAML:

<ListView ItemsSource="{Binding ViewHolders, Mode=TwoWay}" 
          SelectedItem="{Binding SelectedViewHolder, Mode=TwoWay}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <ContentView Content="{Binding Label, Mode="TwoWay"}/>
                <ContentView Content="{Binding Entry, Mode="TwoWay"}/>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

这不是最好的选择,但它对我有用。

另外,如果您添加通过直接关注Entry 触发的OnSelection 事件,您可以将SelectedItem 设置为包含该Entry 的ViewHolder。但这是非常难看的代码(当你看到我上面所做的事情时,这就是在说些什么!)涉及寻找控件父级(和父级父级),直到父级是列表视图(使控件成为视图单元),并将焦点设置为它。

【讨论】:

    【解决方案2】:

    将条目移动到视图模型中,并将条目绑定到 ViewCell 中的ContentView。在ListView.ItemSelected 事件处理程序中,SelectedItem 现在包含条目,您可以在其上调用Focus

    XAML 如下所示:(在此示例中,条目包含一个数量。)

    <ViewCell>
        <StackLayout Orientation="Horizontal">
            <ContentView Content="{Binding QuantityView}" />
            <Label ... />
        </StackLayout>
    </ViewCell>
    

    视图模型如下所示:

    public class MyViewModel {
        public string Quantity {get; set;}
        public Entry QuantityView { get; } = new Entry {...};
    
        public MyViewModel() {
            QuantityView.SetBinding(Entry.TextProperty, nameof(Quantity));
        }
    }
    

    ItemSelected 事件处理程序如下所示:

    void FocusQuantity(object sender, SelectedItemChangedEventArgs e) {
        if (e.SelectedItem == null) return;
        ((MyViewModel)e.SelectedItem).QuantityView.Focus();
    }
    

    【讨论】:

    • 此解决方案违反了 MVVM 原则。为什么?通过将Entry 属性添加到您的 ViewModel,它现在可以了解有关 View 的太多细节。
    • 是的。但在 Xamarin.Forms 允许您 break out of your view model 之前,此解决方法属于 MVVM 纯度规范的 whatugottado 部分。 :-)
    猜你喜欢
    • 1970-01-01
    • 2015-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多