简体   繁体   English

ApplicationBar命令之前的LostFocus

[英]LostFocus before ApplicationBar Command

I'm binding a TextBox to a property of my ViewModel. 我将TextBox绑定到ViewModel的属性。 When the user clicks on an ApplicationBar Button, a command is being called (I'm using BindableApplicationBar, which can be found on NuGet). 当用户单击ApplicationBar按钮时,正在调用命令(我使用的是BindableApplicationBar,可以在NuGet上找到它)。 Problem is that when the user types in the TextBox and clicks right away the Application Button, the setter of the TextBox is not being called, which means that the ButtonCommand is using the old text. 问题在于,当用户键入TextBox并立即单击“应用程序按钮”时,不会调用TextBox的设置器,这意味着ButtonCommand使用的是旧文本。

I've seen a lot of solutions, but I can't use them in my situation. 我已经看到了很多解决方案,但是我无法在自己的情况下使用它们。 The only "solution" would be to get rid of the ApplicationBar and use instead a button, which is behind the Keyboard (which pops up when the user clicks on the TextBox. I'm using Windows Phone, so that's why there's a KeyBoard...). 唯一的“解决方案”是摆脱ApplicationBar并使用一个位于Keyboard后面的按钮(当用户单击TextBox时弹出该按钮。我使用的是Windows Phone,所以这就是为什么有KeyBoard的原因。) ..)。 So the user has to click somewhere else to use the button -> lostfocus. 因此,用户必须单击其他位置才能使用按钮-> lostfocus。

Some solutions: 一些解决方案:

WPF Databind Before Saving 保存之前WPF数据绑定

Binding with UpdateSourceTrigger==LostFocus do not fire for Menu or Toolbar interaction 与UpdateSourceTrigger == LostFocus绑定不会触发菜单或工具栏交互

I cant use UpdateSourceTrigger=PropertyChanged and I'm using MVVM, so I also don't really want to use CodeBehind. 我不能使用UpdateSourceTrigger = PropertyChanged,而且我正在使用MVVM,所以我也不想使用CodeBehind。 If there's no other way to do it without CodeBehind, then it's ok. 如果没有CodeBehind没有其他方法可以做到这一点,那就可以了。

The problem (or bug in the framework?) that is occurring here is that the AppBar is not a real Silverlight control so it's being handled differently in terms of stealing focus. 这里发生的问题(或框架中的错误?)是AppBar不是真正的Silverlight控件,因此在窃取焦点方面的处理方式有所不同。 I'm not sure how this fits into your design, but in one of my apps I used the following pattern: 我不确定这是否适合您的设计,但是在我的一个应用程序中,我使用了以下模式:

    void appBarButton_Click(object sender, EventArgs e)
    {
        // removal of focus from the TextBox to the Page will force the bind.
        this.Focus();

        // wait till the next UI thread tick so that the binding gets updated
        Dispatcher.BeginInvoke(() =>
        {
            // at this point the binding is updated
            MessageBox.Show(RandomText);
        });
    }

This is kind of gross but I used a helper function to wrap a number of different paths that were hitting that so that they didn't have to know about the extra dispatch, or which control was going to steal focus after hitting the button. 这有点麻烦,但是我使用了一个辅助函数来包装许多不同的路径,以使他们不必知道额外的调度,也不必知道哪个控件在按下按钮后会抢走焦点。

One solution I've used in the past is to update the binding whenever the contents of the text box changes, rather than when focus is lost. 我过去使用的一种解决方案是,只要文本框的内容发生更改,而不是失去焦点时,就更新绑定。

A simple, reusable way to do this is with a behaviour. 一个简单,可重用的方法就是行为。

Something like this: 像这样:

public class RebindOnTextChanged : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.TextChanged += this.TextChanged;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        this.AssociatedObject.TextChanged -= this.TextChanged;
    }

    private void TextChanged(object sender, TextChangedEventArgs e)
    {
        var bindingExpression = this.AssociatedObject.GetBindingExpression(TextBox.TextProperty);
        if (bindingExpression != null)
        {
            bindingExpression.UpdateSource();
        }
    } 
}      

and used like: 并像这样使用:

<TextBox Text="{Binding SomeProperty}">
    <i:Interaction.Behaviors>
        <behaviours:RebindOnTextChanged />
    </i:Interaction.Behaviors>
</TextBox>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM