2010-04-21 12 views
5

Durante unos meses he estado utilizando con éxito David Justices Default Button example en mi aplicación SL 3. Este enfoque se basa en una propiedad adjunta.Silverlight 4 Botón predeterminado Servicio

Después de actualizar a SL4, el enfoque ya no funciona, y me da una excepción XAML:

Unknown parser error: Scanner 2148474880

alguien ha utilizado con éxito este (o cualquier otro) de botones predeterminadas comportamientos adjuntos en SL4?

¿Hay alguna otra manera de lograr el comportamiento predeterminado de los botones en SL4 con las nuevas clases que están disponibles?

Gracias, Marcos

Respuesta

2

me ampliado el enfoque de David, al permitir una clave personalizada (por defecto en Enter) para ajustarse en una propiedad adicional:

public static DependencyProperty ButtonKeyProperty = DependencyProperty.RegisterAttached(
     "ButtonKey", 
     typeof(Key), 
     typeof(Defaults), 
     new PropertyMetadata(Key.Enter, ButtonChanged)); 

    public static void SetButtonKey(DependencyObject dependencyObj, Key key) 
    { 
     dependencyObj.SetValue(ButtonKeyProperty, key); 
    } 

    public static Key GetButtonKey(DependencyObject dependencyObj) 
    { 
     return (Key)dependencyObj.GetValue(ButtonKeyProperty); 
    } 

I modificó la propiedad original para aprovechar esta propiedad:

Key key = GetButtonKey(dependencyObj); 
    if (button.IsEnabled && keyEvent.Key == key) 
     ... 

Así que ahora, por ejemplo, puedo usar escape como la clave si quiero (nota que cambió el nombré de las clases y propiedades):

... UI:Defaults.Button="{Binding ElementName=myButton}" UI:Defaults.ButtonKey="Escape" ... 
3

Realmente esperaba que no habría una salida de la solución de caja para un caso de uso tan común en Silverlight 4, pero por desgracia no creo que hay.

Hay otra implementación de botón predeterminado por Patrick Cauldwell. Él también está usando Propiedades Anexas.

He probado esto en una aplicación SL 4 y parece hacer el trabajo.

Puede encontrar el código aquí: http://www.cauldwell.net/patrick/blog/DefaultButtonSemanticsInSilverlightRevisited.aspx

Editar: he pellizcado código de David Justicia para que funcione para Silverlight 4. acabo de modificar la GetDefaultButton y SetDefaultButton tomar y vuelta un DefaultButtonService. El uso es el mismo que se menciona en su sitio web. Esto debería funcionar para usted:

Edit2: ejemplo Agregado XAML para mayor claridad.

public class DefaultButtonService 
    { 
     public static DependencyProperty DefaultButtonProperty = 
      DependencyProperty.RegisterAttached("DefaultButton", 
               typeof(Button), 
               typeof(DefaultButtonService), 
               new PropertyMetadata(null, DefaultButtonChanged)); 

     private static void DefaultButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      var uiElement = d as UIElement; 
      var button = e.NewValue as Button; 
      if (uiElement != null && button != null) 
      { 
       uiElement.KeyUp += (sender, arg) => 
       { 
        if (arg.Key == Key.Enter) 
        { 
         var peer = new ButtonAutomationPeer(button); 
         var invokeProv = 
          peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider; 
         if (invokeProv != null) 
          invokeProv.Invoke(); 
        } 
       }; 
      } 
     } 

     public static DefaultButtonService GetDefaultButton(UIElement obj) 
     { 
      return (DefaultButtonService)obj.GetValue(DefaultButtonProperty); 
     } 

     public static void SetDefaultButton(DependencyObject obj, DefaultButtonService button) 
     { 
      obj.SetValue(DefaultButtonProperty, button); 
     }   
    } 

Cómo aplicar en XAML:

<StackPanel> 
    <TextBox DinnerConfig:DefaultButtonService.DefaultButton="{Binding ElementName=MyButton}" 
       Text="Press Enter" /> 
    <Button x:Name="MyButton" 
      Content="Click me" /> 
</StackPanel> 
+0

Gracias. Los enfoques de David y Patricks son prácticamente iguales, aunque me complace ver que el problema no está en SL4, sino en un escenario particular relacionado con nuestra aplicación. Gracias por tomarse el tiempo para responder +1 –

+0

¿No deberían los métodos "Get/SetDefaultButton" devolver/tomar un botón en lugar de un DefaultButtonService? El tipo en cuestión es el tipo del valor real que se recupera/almacena en la propiedad. Yo mismo hice ese cambio y está funcionando ahora. – Trinition

+0

Sí, Trinition, tienes razón. Si desea agregar un ejemplo, votaré su respuesta como correcta. Puede copiar mi ejemplo agregado de abajo si lo desea. –

0

El problema se debía a un GetDefaultButton método mal escrito. Esto debería haber sido escrita como Button, por ejemplo usando:

public static Button GetDefaultButton(UIElement obj) 
    { 
     return (Button)obj.GetValue(DefaultButtonProperty); 
    } 

en lugar de

public static DefaultButtonService GetDefaultButton(UIElement obj)  
    {  
     return (DefaultButtonService)obj.GetValue(DefaultButtonProperty);  
    } 

funciona como se espera.

HTH otra persona,
Marcos

8

La solución final para nosotros también tuvo que sortear el problema por el que la propiedad de respaldo no se actualizaba antes del clic de botón occuring (como en todos los patrones MVVM) .. .. Nota:peer.SetFocus();

Editar: Agregado XAML ejemplo.

public static class DefaultButtonService 
{ 
    public static DependencyProperty DefaultButtonProperty = 
      DependencyProperty.RegisterAttached("DefaultButton", 
               typeof(Button), 
               typeof(DefaultButtonService), 
               new PropertyMetadata(null, DefaultButtonChanged)); 

    private static void DefaultButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { 
     var uiElement = d as UIElement; 
     var button = e.NewValue as Button; 
     if (uiElement != null && button != null) { 
      uiElement.KeyUp += (sender, arg) => { 
       var peer = new ButtonAutomationPeer(button); 

       if (arg.Key == Key.Enter) { 
        peer.SetFocus(); 
        uiElement.Dispatcher.BeginInvoke((Action)delegate { 

         var invokeProv = 
          peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider; 
         if (invokeProv != null) 
          invokeProv.Invoke(); 
        }); 
       } 
      }; 
     } 

    } 

    public static Button GetDefaultButton(UIElement obj) { 
     return (Button)obj.GetValue(DefaultButtonProperty); 
    } 

    public static void SetDefaultButton(DependencyObject obj, Button button) { 
     obj.SetValue(DefaultButtonProperty, button); 
    }  
} 

Cómo aplicar en XAML:

<StackPanel> 
    <TextBox DinnerConfig:DefaultButtonService.DefaultButton="{Binding ElementName=MyButton}" 
       Text="Press Enter" /> 
    <Button x:Name="MyButton" 
      Content="Click me" /> 
</StackPanel> 
0

Aquí es una manera fácil de conectar un botón predeterminado cuando se pulsa ENTER:

Por razones de seguridad, Silverlight no permitirá que se llama a una manejador de botones directamente en el código, por lo que tenemos que crear una nueva rutina que se pueda llamar, luego tener el manejador de botones y el manejador de teclas de forma llamar a esta rutina.

Paso 1: hacer una rutina y poner todo en lo que la rutina botón tenía

private void DoSharedRoutine(){ // do something } 

Paso 2: han llamado controlador de botón compartida rutina

private void Login_Click(object sender, System.Windows.RoutedEventArgs e) 
    { 
     DoSharedRoutine(); 
    } 

Paso 3: se han keyDown manejador de su panel que contiene su botón llame a la rutina compartida

private void MyGrid_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) 
    { 
     if (e.Key == Key.Enter) DoSharedRoutine(); 
    } 
Cuestiones relacionadas