Подтвердить что ты не робот

WPF-MVVM: настройка фокуса управления пользовательским интерфейсом из ViewModel

Какова хорошая практика настройки фокуса управления в архитектуре MVVM.

Как я себе это представляю, это свойство на ViewModel, которое может вызвать изменение фокуса, когда это необходимо. И чем управляющие элементы интерфейса связывают/прослушивают это свойство, так что если он изменится, будет установлен соответствующий фокус.

Я рассматриваю его как объект ViewModel, потому что хочу установить фокус, соответствующий после того, как определенное действие было выполнено ViewModel, например, загрузка определенных данных.

Какая лучшая практика?

4b9b3361

Ответ 2

Если вы используете Caliburn.Micro, вот сервис, который я создал, чтобы установить Focus на любой элемент управления в виде, унаследованном от экрана.

Примечание: Это будет работать, только если вы используете Caliburn.Micro для своей инфраструктуры MVVM.

public static class FocusManager
{
    public static bool SetFocus(this IViewAware screen ,Expression<Func<object>> propertyExpression)
    {
        return SetFocus(screen ,propertyExpression.GetMemberInfo().Name);
    }

    public static bool SetFocus(this IViewAware screen ,string property)
    {
        Contract.Requires(property != null ,"Property cannot be null.");
        var view = screen.GetView() as UserControl;
        if ( view != null )
        {
            var control = FindChild(view ,property);
            bool focus = control != null && control.Focus();
            return focus;
        }
        return false;
    }

    private static FrameworkElement FindChild(UIElement parent ,string childName)
    {
        // Confirm parent and childName are valid. 
        if ( parent == null || string.IsNullOrWhiteSpace(childName) ) return null;

        FrameworkElement foundChild = null;

        int childrenCount = VisualTreeHelper.GetChildrenCount(parent);

        for ( int i = 0; i < childrenCount; i++ )
        {
            FrameworkElement child = VisualTreeHelper.GetChild(parent ,i) as FrameworkElement;
            if ( child != null )
            {

                BindingExpression bindingExpression = GetBindingExpression(child);
                if ( child.Name == childName )
                {
                    foundChild = child;
                    break;
                }
                if ( bindingExpression != null )
                {
                    if ( bindingExpression.ResolvedSourcePropertyName == childName )
                    {
                        foundChild = child;
                        break;
                    }
                }
                foundChild = FindChild(child ,childName);
                if ( foundChild != null )
                {
                    if ( foundChild.Name == childName )
                        break;
                    BindingExpression foundChildBindingExpression = GetBindingExpression(foundChild);
                    if ( foundChildBindingExpression != null &&
                        foundChildBindingExpression.ResolvedSourcePropertyName == childName )
                        break;
                }

            }
        }

        return foundChild;
    }

    private static BindingExpression GetBindingExpression(FrameworkElement control)
    {
        if ( control == null ) return null;

        BindingExpression bindingExpression = null;
        var convention = ConventionManager.GetElementConvention(control.GetType());
        if ( convention != null )
        {
            var bindablePro = convention.GetBindableProperty(control);
            if ( bindablePro != null )
            {
                bindingExpression = control.GetBindingExpression(bindablePro);
            }
        }
        return bindingExpression;
    }
}

Как это использовать?

Из вашего ViewModel, унаследованного от Caliburn.Micro.Screen или Caliburn.Micro.ViewAware

this.SetFocus(()=>ViewModelProperty);  или this.SetFocus("Property");

Как это работает?

Этот метод попытается найти элемент в визуальном дереве просмотра, а фокус будет установлен на любой соответствующий элемент управления. Если такой контроль не найден, тогда он будет использовать BindingConventions, используемые Caliburn.Micro.

Например,

Он будет искать правильность в BindingExpression элемента управления. Для TextBox он будет смотреть, будет ли это свойство привязано к свойству Text, тогда фокус будет установлен.

Ответ 3

ViewModel выдает событие в представление, сообщающее ему, что действие завершено, и представление будет устанавливать фокус.

Ответ 4

Вы можете ввести интерфейс для представления, чтобы ViewModel мог указать View, чтобы установить Focus. Пример использования BookLibrary приложения WPF Application Framework (WAF) показывает, как это сделать. Посмотрите на BookListViewModel.

Ответ 5

Вопрос задан несколько раз, к сожалению, ответы применимы только к WPF. Таким образом, для серебряного света с использованием MVVM вы также можете связываться с любым свойством для подробностей, пожалуйста, перейдите по следующей ссылке

http://codenicely.blogspot.com/2012/01/how-to-set-textbox-focus-in-silverlight.html