WPF-MVVM: Настройка фокуса управления пользовательским интерфейсом из ViewModel - PullRequest
45 голосов
/ 17 марта 2011

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

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

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

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

Ответы [ 5 ]

29 голосов
/ 17 марта 2011

Используйте прикрепленное свойство IsFocused, как указано в разделе «Ответ здесь»: Установите фокус на текстовое поле в WPF из модели представления (C #)

Затем вы можете просто привязать свойство к вашей модели представления.

14 голосов
/ 05 января 2014

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

Примечание: Это будет работать только в том случае, если вы используете 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");

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

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

Например,

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

1 голос
/ 17 марта 2011

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

0 голосов
/ 19 января 2012

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

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

0 голосов
/ 24 марта 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...