在ListView项目选择上关注ViewCell条目

时间:2018-02-15 15:45:25

标签: listview xamarin.forms

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

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

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

2 个答案:

答案 0 :(得分:2)

将Entry移动到视图模型中,并将Entry绑定到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();
}

答案 1 :(得分:0)

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

<强> Viewholder:

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 Parent):

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>

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

此外,如果您添加OnSelection事件,该事件是通过直接关注Entry而触发的,则可以将SelectedItem设置为包含Entry的ViewHolder。但它是非常丑陋的代码(当你看到我上面做过的事情时,它会说些什么!)参与寻找控制父母(和父母的父母)直到父母是列表视图(制作控制一个视单元),并将焦点设置到它。