【问题标题】:How to set focus from ViewModel in Xamarin Forms如何在 Xamarin Forms 中从 ViewModel 设置焦点
【发布时间】:2015-11-19 06:53:48
【问题描述】:

我想在做一些异步操作后设置焦点SearchBox控件中,我想我的ViewModel强>。

我怎么可能做到这一点?

编辑

ViewModel 代码:

    private bool _searchBarFocused;

    public bool SearchBarFocused
    {
        get { return _searchBarFocused; }
        set
        {
            _searchBarFocused = value;
            base.OnPropertyChanged("SearchBarFocused");
        }
    }

    public async Task InitializeData()
    {
        // Other operations...

        SearchBarFocused = true;
    }

View 的代码隐藏代码:

    protected override void OnAppearing()
    {
        base.OnAppearing();
        (this.BindingContext as MyViewModel).InitializeData();
    }

搜索栏 XAML 代码:

  <SearchBar SearchCommand="{Binding SearchItemsCommand}">
    <SearchBar.Triggers>
      <DataTrigger TargetType="SearchBar"
                   Binding="{Binding SearchBarFocused, Mode=TwoWay}" Value="True">
        <Trigger.EnterActions>
          <triggers:SearchBarFocusTriggerAction Focused="True" />
        </Trigger.EnterActions>

        <Trigger.ExitActions>
          <triggers:SearchBarFocusTriggerAction Focused="False" />
        </Trigger.ExitActions>
      </DataTrigger>
    </SearchBar.Triggers>
  </SearchBar>

触发动作代码:

public class SearchBarFocusTriggerAction : TriggerAction<SearchBar>
{
    public bool Focused { get; set; }

    protected override void Invoke(SearchBar searchBar)
    {
        if (Focused)
            searchBar.Focus();
        else
            searchBar.Unfocus();
    }
}

【问题讨论】:

    标签: c# xaml focus viewmodel xamarin-forms


    【解决方案1】:

    其中一个选项是使用触发器(XAML 方式):

     <SearchBar x:Name="searchBar"
           Text=""
           Placeholder="type something">
        <SearchBar.Triggers>
    
            <DataTrigger TargetType="SearchBar"
                         Binding="{Binding ViewModelIsSearchBarFocused}"
                         Value="True">
    
                <Trigger.EnterActions>
                    <local:FocusTriggerAction Focused="True" />
                </Trigger.EnterActions>
    
                <Trigger.ExitActions>
                    <local:FocusTriggerAction Focused="False" />
                </Trigger.ExitActions>
    
            </DataTrigger>   
    
            <EventTrigger Event="Unfocused">
                <local:UnfocusedTriggerAction />
            </EventTrigger>    
    
        </SearchBar.Triggers>       
    </SearchBar>
    
    public class FocusTriggerAction : TriggerAction<SearchBar>
    {
        public bool Focused { get; set; }
    
        protected override async void Invoke (SearchBar searchBar)
        {
            await Task.Delay(1000);
    
            if (Focused)
            {
                searchBar.Focus();
            }
            else
            {
                searchBar.UnFocus();
            }
        }
    }
    
    public class UnfocusedTriggerAction : TriggerAction<SearchBar>
    {
        protected override void Invoke (SearchBar searchBar)
        {
            YourViewModel.ViewModelIsSearchBarFocused = false;
        }
    }
    

    在此处阅读更多信息:https://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/triggers/

    【讨论】:

    • 感谢您的回复,丹尼尔。我在我的项目中使用了您的方法,它似乎有效,但是仅在我第一次将 ViewModelIsSearchBarFocused 值分配为 true 时才提出 Invoke 方法。其余时间不调用此方法...你知道为什么吗?
    • 您的 ViewModel 是否正确实现了 IOnNotifyPropertyChanged?我需要你的 ViewModel 代码来了解原因。
    • 是的,确实如此。我刚刚用我正在使用的源代码更新了这个问题。它在第一次调用 InitializeData() 方法时有效,但在第二次调用时无效...
    • 我认为是因为在UI中失去焦点时,ViewModelIsSearchBarFocused属性没有设置为false。有可能吗?
    • Trigger.EnterActionsTrigger.ExitActions 应分别重命名为 DataTrigger.EnterActionsDataTrigger.ExitActions
    【解决方案2】:

    这是我如何做的一个例子,在此之前我曾经使用 MessagingCenter 做

    在 xaml 中,您需要为要聚焦的 obj 提供一个 x:Name。

    <!-- PICKER's DEFINITION -->
    <DatePicker
        x:Name="Datepicker"
        Date="{Binding SelectedDate, Mode=TwoWay}"
        IsEnabled="true"
        IsVisible="false">
    </DatePicker>
    

    那么您必须在按钮上的命令参数中引用该控件,或者例如在这种情况下我使用工具栏项。

    <!-- MENU TOOLBAR -->
    <ContentPage.ToolbarItems>
        <ToolbarItem
            Command="{Binding ShowCalendarCommand}"
            Icon="Calendar"
            CommandParameter="{x:Reference Datepicker}" />
    </ContentPage.ToolbarItems>
    

    然后在你的 vm 命令中:

    #region toolbar commands
    
    public ICommand ShowCalendarCommand => new RelayCommand<Object>(ShowCalendar);
    
    #endregion
    
    private void ShowCalendar(Object obj)
    {
        var calendar = (DatePicker)obj;
        calendar.Focus();
        //  MessagingCenter.Send(this, "Calendar");
    }
    

    【讨论】:

    • 例如,如果我想在每次在 Entry 中键入字符时重新关注视图,该怎么办。假设我使用 entry 或 SearchBar 进行搜索,并且在输入的每个字符上,我希望进行过滤。但是我的过滤逻辑导致条目失去焦点,所以最后我想重新关注那个条目,以便用户可以输入下一个字符。
    【解决方案3】:

    我通过将 contentpage 作为参数传递给 viewmodel 解决了我的问题

    BindingContext = new YourViewModel(this);
    

    并在视图模型中创建了一个属性

    public ContentPage m_View { get; set; }
    

    然后从构造函数中设置这个属性的值

     public YourViewModel(ContentPage view)
        {
            m_View = view;
        }
    

    然后通过使用它的名称将焦点设置在我的 DatePicker 上

      var DatePicker = m_View.FindByName("YourDatePickerName") as DatePicker;
      DatePicker.Focus();
    

    我的 DatePicker 代码是

     <DatePicker x:Name="YourDatePickerName"
                 Date="{Binding SelectedDate}" />
    

    【讨论】:

    • 我相信您的回答被否决了,因为在 MVVM 的上下文中它通常被认为是一种丑陋的方法。 ViewModel 不应该知道任何关于视图的信息,ViewModel 和 View 之间的通信应该是单向的,以保持代码库的灵活性。
    猜你喜欢
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-14
    • 2011-07-17
    • 2023-01-07
    • 2019-07-29
    • 1970-01-01
    相关资源
    最近更新 更多