【问题标题】:How to get Label view in ViewModel to set accessibility focus in xamarin forms如何在 ViewModel 中获取标签视图以在 xamarin 表单中设置可访问性焦点
【发布时间】:2021-07-13 12:57:05
【问题描述】:

我有Label 视图,我需要ViewModel 中的Label 视图。我正在使用 Dependency Service 将重点放在 Controls for Accessibility 服务上,DS 需要 view 作为参数。

这是我的标签

<Label
    AutomationProperties.IsInAccessibleTree="{Binding ShowNoResults}"
    IsVisible="{Binding ShowNoResults}"
    Text="{Binding ResultsHeader}"/>

我试过Command,但标签不支持命令。下面的代码也不起作用

var view = GetView() as HomeworkView;

我收到view 总是null。我该如何解决这个问题?

【问题讨论】:

  • 您的虚拟机不应直接访问您的视图。
  • @Jason - 如果特定操作没有返回任何内容,我该如何将焦点设置在noResult Label
  • 我不清楚您要做什么 - 将焦点设置在不接受键盘输入的元素上不会完成任何事情。我不是可访问性专家,但我建议让您的 VM 引发您的视图订阅的自定义事件,这将告诉它在哪里设置可访问性焦点。
  • @Jason - 辅助功能适用于盲人。 Label 文本将被宣布 Like no result found,为此,Label 需要关注。让我探索更多。
  • 为什么需要手动设置辅助功能焦点?您可以使用Xamarin Forms - Automation Properties 实现您的目标吗?

标签: xamarin xamarin.forms accessibility


【解决方案1】:

我不太确定您要实现什么,但您无法从您的视图模型访问视图元素。

如果你想对控件做点什么,你可以使用消息中心来做,这里是一个例子

在您的视图模型中

MessagingCenter.Send(this, "your message here");

然后在您的页面中,您需要从该视图模型订阅此消息并执行所需的操作

MessagingCenter.Instance.Unsubscribe<ViewModelClassNamedel>(this, "your message here");    
MessagingCenter.Instance.Subscribe<ViewModelClassName>(this, "your message here", (data) =>
    {
        this.youControlName.Focus();
    });

【讨论】:

    【解决方案2】:

    更多细节添加到Mohammad's answer

    Message Center doc.

    在您的 ViewModel 中(类名为“YourViewModel”):

    // Here we use control name directly.
    // OR could make an "enum" with a value for each control.
    string controlName = ...;
    MessagingCenter.Send<YourViewModel>(this, "focus", controlName);
    

    然后在您的页面中,订阅此消息并执行所需的操作

    .xaml.cs:

    protected override void OnAppearing() {
    {
        base.OnAppearing();
    
        // Unsubscribe before Subscribe ensures you don't Subscribe twice, if the page is shown again.
        MessagingCenter.Instance.Unsubscribe<YourViewModel>(this, "focus");    
        MessagingCenter.Instance.Subscribe<YourViewModel>(this, "focus", (controlName) =>
        {
            View v = null;
            switch (controlName) {
            case "name1":
                v = this.name1;
                break;
            case "name2":
                v = this.name2;
                break;
            }
    
            if (v != null) {
                //v.Focus();
                // Tell VM to use v as view.
                ((YourViewModel)BindingContext).SetFocus(v);
            }
        });
    }
    
    protected override void OnDisappearing() {
        MessagingCenter.Instance.Unsubscribe<YourViewModel>(this, "focus");    
    
        base.OnDisappearing();
    }
    

    如果需要将View v 传递回VM,因为那有使用它的逻辑:

    public class YourViewModel
    {
    
        public void SetFocus(View view)
        {
           ... your code that needs label's view ...
        }
    }
    

    未测试。可能需要一些细微的改变。可能需要

    ...(this, "focus", (sender, controlName) =>
    

    而不是

    ...(this, "focus", (controlName) =>
    

    更新

    简单的方法,如果 VM 中只需要一个视图。

    public class YourViewModel
    {
        public View ViewToFocus { get; set; }
    
        // The method that needs ViewToFocus.
        void SomeMethod()
        {
            ...
            if (ViewToFocus != null)
                ... do something with it ...
        }
    }
    
    public class YourView
    {
        public YourView()
        {
            InitializeComponent();
            ...
            // After BindingContext is set.
            ((YourViewModel)BindingContext).ViewToFocus = this.yourLabelThatShouldBeFocused;
        }
    
    }
    

    替代方案:在页面的 OnAppearing 中设置 ViewToFocus 并在 OnDisappearing 中清除它可能会更清晰/更健壮。这确保了在页面不可见时(或页面消失后的某些延迟操作)永远不会使用它。我可能会这样做。

    protected override void OnAppearing()
    {
        base.OnAppearing();
        ((YourViewModel)BindingContext).ViewToFocus = this.yourLabelThatShouldBeFocused;
    }
    
    protected override void OnDisappearing()
    {
        ((YourViewModel)BindingContext).ViewToFocus = null;
        base.OnDisappearing();
    }
    

    【讨论】:

    • viewmodel no overloads takes 3 argument for Send 中的第一个问题SubscribeOnAppearing 中的第二个问题Subscribe 中没有像lbl.focus 这样的方法,而我需要使用这一行DependencyService.Get&lt;ISetAccessibleFocus&gt;().AccessibilityFocus(noResultLblHeader); 我该如何解决这个问题跨度>
    • @R15 - 也许是Send&lt;YourViewModel, string&gt;。您可能还需要将订阅/取消订阅更改为&lt;YourViewModel, string&gt;。我试图从一个例子中改编代码。您必须进行试验或搜索更多信息。
    • @R15 - 我已经编辑以显示如何将标签的视图传递回YourViewModel 中的函数。
    • @R15 noResultLblHeader 是什么?如果发生特定操作,您想使用DependencyService.Get&lt;ISetAccessibleFocus&gt;().AccessibilityFocus(noResultLblHeader);
    • @CherryBu-MSFT - 是的,如果搜索没有返回结果,那么我们将在屏幕中间显示Label,如No Result FoundnoResultLblHeader 是标签名称。当没有找到记录时,我需要使用 Dep Service 宣布该标签。
    猜你喜欢
    • 2015-11-19
    • 1970-01-01
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-08
    • 2023-03-02
    相关资源
    最近更新 更多