在ListView项选择上聚焦ViewCell项

在ListView项选择上聚焦ViewCell项,listview,xamarin.forms,Listview,Xamarin.forms,我有一个Xamarin.Forms ListView和一个自定义ViewCell,其中包含一个带有条目和标签的StackLayout。我希望该条目在选择ViewCell时获得焦点 ItemSelected提供选定的项目,但不提供ViewCell。我可以为ViewCell创建自定义类,但我不知道它如何知道何时被选中 如何将条目集中在ListView项目选择上?我这样做的方式是创建一个类-Viewholder-它包含您想要的两个视图。然后将其用于ListView ItemSource,并关注Sele

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

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


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

我这样做的方式是创建一个类-Viewholder-它包含您想要的两个视图。然后将其用于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));
    }
}
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);
        }
    }    
}
<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>
主页(ListView父级):

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));
    }
}
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);
        }
    }    
}
<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>
public类主页:ContentPage
{
公共主页(){
设置控件();
}
私人可观察收藏(viewholder);;
公共可观测集合视图持有者
{
获取{return\u viewHolders;}
设置{
如果(值!=null&&
_视图持有者!=值){
_视图持有者=值;
OnPropertyChanged();
}
}
私有视图持有者_选择的视图持有者;
公共视图持有者已选择视图持有者{
获取{return\u selectedViewHolder;}
设置{
如果(值!=null&&
_selectedViewHolder!=值){
_selectedViewHolder=值;
OnPropertyChanged();
_selectedViewHolder.OnFocus();
}
}
专用控件(列表l){
foreach(l中的变量s){
ViewHolder v=新的ViewHolder{
标签=新标签{
Text=s,
};    
条目=新条目();
};
视图持有者。添加(v);
}
如果(l.计数>0){
SelectedViewHolder=ViewHolders.ElementAt(0);
}
}    
}
XAML:

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));
    }
}
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);
        }
    }    
}
<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事件,您可以将SelectedItem设置为包含该条目的ViewHolder。但是这是一个非常难看的代码(当您看到我在上面所做的工作时,这说明了这一点!)涉及到查找控件父级(和父级)直到父对象成为listview(使控件成为viewcell),并将焦点设置为它。

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

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


视图模型如下所示:

公共类MyViewModel{
公共字符串数量{get;set;}
公共条目QuantityView{get;}=新条目{…};
公共MyViewModel(){
QuantityView.SetBinding(Entry.TextProperty,nameof(Quantity));
}
}
ItemSelected
事件处理程序如下所示:

void FocusQuantity(对象发送方,SelectedItemChangedEventArgs e){
if(e.SelectedItem==null)返回;
((MyViewModel)e.SelectedItem.QuantityView.Focus();
}

stacklayout上的点击手势可以忽略所选内容,重定向操作以聚焦条目吗?点击可能不会产生选择。例如,添加新项目时,会自动选中该项目,其条目应自动聚焦。您是否可以获取该项目的索引,然后抓取ViewCell手动基于索引?此解决方案违反了MVVM原则。为什么?通过向ViewModel添加
条目
属性,它现在知道了太多关于View.Yup的细节。但在Xamarin.Forms允许之前,此解决方案属于MVVM纯度规范的whatugottado部分:-)