【问题标题】:How to set focus to a control with Caliburn.Micro MVVM如何使用 Caliburn.Micro MVVM 将焦点设置到控件
【发布时间】:2010-12-31 17:08:37
【问题描述】:

我有一个表单,我想在某些用户操作发生时将焦点设置到文本框。我知道 MVVM 的处理方式是绑定到 VM 属性,但是 TextBox 没有允许这种情况发生的属性。从 VM 设置焦点的最佳方式是什么?

【问题讨论】:

    标签: c# silverlight mvvm caliburn.micro


    【解决方案1】:

    我创建了一个 IResult 实现,它可以很好地实现这一目标。您可以从 IResult 的 ActionExecutionContext 中获取视图,然后您可以搜索(我按名称搜索)您想要关注的控件。

    public class GiveFocusByName : ResultBase
    {
        public GiveFocusByName(string controlToFocus)
        {
            _controlToFocus = controlToFocus;
        }
    
        private string _controlToFocus;
    
        public override void Execute(ActionExecutionContext context)
        {
            var view = context.View as UserControl;
    
    
            // add support for further controls here
            List<Control> editableControls =
                    view.GetChildrenByType<Control>(c => c is CheckBox ||
                                                          c is TextBox ||
                                                          c is Button);
    
            var control = editableControls.SingleOrDefault(c =>
                                                     c.Name == _controlToFocus);
    
            if (control != null)
            control.Dispatcher.BeginInvoke(() =>
            {
                control.Focus();
    
                var textBox = control as TextBox;
                if (textBox != null)
                    textBox.Select(textBox.Text.Length, 0);
            });
    
            RaiseCompletedEvent();
        }
    }
    

    viewChildWindow 时,我省略了一些额外的代码来从context 获取view,如果您需要,我可以提供。

    GetChildrenByType 也是一个扩展方法,这里是许多可用的实现之一:

    public static List<T> GetChildrenByType<T>(this UIElement element,
                              Func<T, bool> condition) where T : UIElement
    {
        List<T> results = new List<T>();
        GetChildrenByType<T>(element, condition, results);
        return results;
    }
    
    private static void GetChildrenByType<T>(UIElement element,
                              Func<T, bool> condition, List<T> results) where T : UIElement
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
        {
            UIElement child = VisualTreeHelper.GetChild(element, i) as UIElement;
            if (child != null)
            {
                T t = child as T;
            if (t != null)
            {
                if (condition == null)
                    results.Add(t);
                else if (condition(t))
                results.Add(t);
            }
            GetChildrenByType<T>(child, condition, results);
            }
        }
    }
    

    您的操作将类似于以下内容(以 Caliburn.Micro ActionMessage 样式调用)。

    public IEnumerable<IResult> MyAction()
    {
        // do whatever
        yield return new GiveFocusByName("NameOfControlToFocus");
    }
    

    【讨论】:

    • 由于某种原因,Execute() 方法上的 ActionExecutionContext 参数始终为空。为了解决这个问题,我在 OnViewLoaded(object view) 虚拟方法之后调用协程,然后创建一个新的ActionExecutionContext() { View = (DependencyObject)view });
    • @JohnPolvora 不知道为什么会这样,你是如何调用使用这个 IResult 的协程的?
    • 在从 Screen 基类派生的视图模型中,首先我尝试调用 IResult 覆盖 OnActivate。但是在 OnActivate 似乎该视图不适用于协程的执行上下文。我使用 Coroutine.BeginExecute 调用
    • @JohnPolvora 是的,框架不会将 OnActivate 作为协程调用,您的解决方案将正常工作,我将虚拟 ViewLoaded 协程添加到我的 ScreenBase,然后通过 Action 从需要的视图中调用它它,只是省去了自己创建上下文。
    猜你喜欢
    • 1970-01-01
    • 2011-06-09
    • 1970-01-01
    • 2017-01-21
    • 2011-07-17
    • 2014-01-21
    • 1970-01-01
    • 2023-01-07
    • 2016-10-22
    相关资源
    最近更新 更多