【问题标题】:Silverlight 4 Default Button ServiceSilverlight 4 默认按钮服务
【发布时间】:2010-04-21 14:37:00
【问题描述】:

几个月来,我在我的 SL 3 应用程序中成功使用了David Justices Default Button example。此方法基于附加属性。

升级到 SL4 后,该方法不再有效,并且出现 XAML 异常:

未知的解析器错误:扫描仪 2148474880

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

有没有其他方法可以使用可用的新类在 SL4 中实现默认按钮行为?

谢谢, 标记

【问题讨论】:

    标签: silverlight-4.0 attached-properties defaultbutton


    【解决方案1】:

    我们的最终解决方案还必须解决在按钮单击发生之前没有更新支持属性的问题(就像在所有 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>
    

    【讨论】:

      【解决方案2】:

      我真的希望 Silverlight 4 中的这种常见用例有一个开箱即用的解决方案,但不幸的是我认为没有。

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

      我已经在 SL 4 应用程序中对此进行了测试,它似乎可以完成这项工作。

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

      编辑: 我已经调整了 David Justice 的代码以使其适用于 Silverlight 4。我刚刚更改了 GetDefaultButton 和 SetDefaultButton 以获取并返回 DefaultButtonService。用法与他网站上的说明相同。 这应该适合你:

      编辑2: 为了清楚起见,添加了 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>
      

      【讨论】:

      • 谢谢。 David 和 Patricks 的方法几乎完全相同——尽管我很高兴看到问题不在于 SL4,而必须是与我们的应用程序相关的特定场景。感谢您抽出宝贵时间回复 +1
      • “Get/SetDefaultButton”方法不应该返回/采用 Button 而不是 DefaultButtonService?有问题的类型是在属性中检索/存储的实际值的类型。我自己做了这个改变,现在它正在工作。
      • 是的,Trinition,你是对的。如果您想添加一个示例,我会将您的答案投票为正确。如果您愿意,可以复制我从下面添加的示例。
      【解决方案3】:

      我通过允许在附加属性中设置自定义键(默认为 Enter)来扩展 David 的方法:

          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)
              ...
      

      所以现在,例如,我可以根据需要使用 Escape 作为键(注意我更改了类和属性的名称):

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

      【讨论】:

        【解决方案4】:

        问题是由输入错误的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 别人,
        标记

        【讨论】:

          【解决方案5】:

          这是一种在按下回车键时连接默认按钮的简单方法:

          出于安全原因,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();
               }
          

          【讨论】:

            猜你喜欢
            • 2017-10-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多