2010-04-21 52 views
5

几个月来,我一直在我的SL 3应用程序中成功使用David Justices Default Button example。这种方法基于附属性。Silverlight 4默认按钮服务

升级到SL4后,该方法不再起作用了,我得到一个XAML例外:

Unknown parser error: Scanner 2148474880

有没有人成功地使用这个(或任何其他)在SL4默认按钮附加的行为?

有没有其他的方式来实现SL4中的默认按钮行为与新的类可用?

谢谢, 马克

回答

2

我伸出大卫的做法,允许自定义键(默认为输入)的一个附加属性进行设置:

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); 
    } 

我修改原来的财产,然后利用此属性:

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

所以现在,例如,我可以使用转义为关键,如果我想(注意,我改变了命名的种类和属性):

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

我真的很希望会有一个开箱即用解决方案的这种共同的用例在Silverlight 4中,但不幸的是,我不觉得有什么。

Patrick Cauldwell还有另一个默认按钮实现。他也在使用附加属性。

我已经在SL 4应用程序中测试过它,它似乎完成了这项工作。

您可以在这里找到代码: http://www.cauldwell.net/patrick/blog/DefaultButtonSemanticsInSilverlightRevisited.aspx

编辑: 我已经调整了大卫正义的代码来得到它的工作为Silverlight 4,我只是改变了GetDefaultButton和SetDefaultButton采取与回报一个DefaultButtonService。用法与他网站上的说明相同。 这应该为你工作:

EDIT2: 新增XAML例如,对于清晰度。

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); 
     }   
    } 

如何在XAML应用:

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

谢谢。大卫和帕特里克的方法几乎完全一样 - 虽然我很高兴看到这个问题不在SL4中,但是我们的应用程序必须有一个特定的场景。感谢您花时间回复+1 – 2010-04-29 11:31:48

+0

“Get/SetDefaultButton”方法不应该返回/取得一个Button而不是DefaultButtonService吗?有问题的类型是正在检索/存储在属性中的实际值的类型。我自己做了这个改变,现在它正在工作。 – Trinition 2010-05-26 13:58:43

+0

是的,Trinition,你是对的。如果你想添加一个例子,我会投票你的答案是正确的。如果您愿意,可以复制我从下面添加的示例。 – 2010-05-28 11:11:27

0

的问题是由输入不佳GetDefaultButton方法造成的。这本来是类型为Button,例如使用:的

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

代替

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

按预期工作。

HTH别人,
马克

8

对我们来说,最终的解决方案还必须得到解决,其中后备财产没有被之前的按钮,点击发生的历史(如在所有的MVVM模式)更新的问题.. .. 注:peer.SetFocus();

编辑: 新增XAML例子。

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); 
    }  
} 

如何在XAML应用:

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

这里是进入被按下时,连接一个默认的按钮,一个简单的方法:

出于安全原因,Silverlight将不会让你叫按钮处理程序直接在代码中,所以我们必须创建一个可以调用的新例程,然后让按钮处理程序和表单keydown处理程序都调用此例程。

第1步:按常规,把一切都在它的按钮程序有

private void DoSharedRoutine(){ // do something } 

第2步:有按钮处理程序调用共享日常

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

步骤3:已KEYDOWN的处理程序包含按钮的面板调用共享例程

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