开发者

XAML Default Button call and Binding

Surely I'm doing something wrong, however, I don't know what.

I have a default button inside a WPF User Control, like this:

<Button Name="btnProcessar" 
        Width="80"
        Height="24"
        Click="btnProcessar_Click"
        Content="_Buscar"
        ToolTip="Buscar" 
        IsDefault="True"/>

The first control inside the grid is a TextBox, like this:

        <TextBox Name="txtCodigo" 
                 Width="100"
                 Height="26"
                 Margin="5,0,0,0"
                 MaxLength="8"
                 ToolTip="Preencher com parte do código do Serviço Composto buscado.">
            <Binding Mode="TwoWay" Path="TarefaBuscarServicosCompostos.Codigo" />
        </TextBox>

Never mind the Path, just know that TarefaBuscarServicosCompostos is my VM (of sorts). When I hit enter on my keyboard while the TextBox has focus the Click event is fired up as expected, so I can check (through debugging) that btnProcessar_Click is called.

The problem is the bind; You see, TarefaBuscarServicosCompostos.Codigo has no data when the event is raised. It's clear to me that WPF is not resolving binds before calling the code be开发者_如何转开发hind to treat the event.

  1. Why is that? Shouldn't all binds be evaluated before the call to btnProcessar_Click is made?
  2. Is there a way to force WPF to evaluate binds from btnProcessar_Click?
  3. Is there a better approach to this problem? How am I expected to deal with events while also using binds?

Thanks a lot. Any help is appreciated, of course.


You have multiple options. The most simple would be to set the UpdateSourceTrigger of the binding to UpdateSourceTrigger=Property. Another possibility is to execute the binding manually in btnProcessar over BindingExpression


I have come up with another solution to this problem. for those who don't want to change every single Binding on their forms (or even worst create a new Binding class) you can use the following attached property on your UserControl or Window (or any other ContentControl) which make the default button take focus before the Command executes. And solves the binding problem.

public class DefaultButtonBehavior
{
    private static readonly DependencyProperty EnableProperty = DependencyProperty.RegisterAttached(
    "Enable", typeof(bool), typeof(ContentControl), new PropertyMetadata(false, PropertyChangedCallback));
    public static void SetEnable(DependencyObject obj, bool value)
    {
        obj.SetValue(EnableProperty, value);
    }

    public static bool GetEnable(DependencyObject obj)
    {
        return (bool)obj.GetValue(EnableProperty);
    }

    private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
    {
        var control = dependencyObject as ContentControl;
        if (control == null)
            return;

        control.Loaded += (sender, args) =>
        {
            var depthStack = new Stack<int>();
            var index = 0;
            var parent = dependencyObject;
            while (depthStack.Count > 0 || index < VisualTreeHelper.GetChildrenCount(parent))
            {
                while (index == VisualTreeHelper.GetChildrenCount(parent) && depthStack.Count > 0)
                {
                    parent = VisualTreeHelper.GetParent(parent);
                    index = depthStack.Pop();
                }

                if (index == VisualTreeHelper.GetChildrenCount(parent))
                    break;

                var child = VisualTreeHelper.GetChild(parent, index);
                if (child is Button)
                    if(((Button)child).IsDefault)
                    ((Button)child).Click += ButtonOnClick;

                if (VisualTreeHelper.GetChildrenCount(child) > 0)
                {
                    parent = child;
                    index++;
                    depthStack.Push(index);
                    index = 0;
                }
                else
                    index++;
            }
        };
    }

    private static void ButtonOnClick(object sender, RoutedEventArgs routedEventArgs)
    {
        var button = sender as Button;

        button?.Focus();
    }
}

You can use it this way

<UserControl
        ...
        common:DefaultButtonBehavior.Enable="True">
        .
        .
        .
        <Button Command="{Binding SaveCommand}" 
                IsDefault="True"
                ...
                 />
</UserControl>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜