SplitButtoning hairs [Two fixes for my Silverlight SplitButton/MenuButton implementation – and true WPF support]


This blog has moved to a new location and comments have been disabled.

All old posts, new posts, and comments can be found on The blog of dlaa.me.

See you there!

Comments (31)
  1. Hi David,

    You're  SplitButton is absolutly awsome. I 'm using it on different project and the only problem i 've encountering, was about Zoom.

    Now, all is perfect ! Thanks a lot !

  2. David Anson says:

    Samuel,

    Thanks for the kind words! 🙂

  3. Fabio says:

    Hi David,

    your Control is beautiful but it's not responding to command properly (WPF version). Menu items appear always grayed out.

    is this a bug?

    thanks

    Fabio

  4. David Anson says:

    Fabio,

    I just tried this and found a problem that may be what you're seeing as well. The ContextMenu (on WPF; I haven't tried on Silverlight) isn't inheriting the DataContext from the SplitButton parent, so the Command Bindings on the MenuItem don't map to anything and aren't hooked up right. I'd expect this to leave the MenuItems in the default IsEnabled=true state, but maybe you're changing that?

    At any rate, adding the following to the list of properties for the ContextMenu element inside the SplitButton/MenuButton Template in Generic.xaml fixed the problem I was seeing:

    DataContext="{TemplateBinding DataContext}"

    This is probably a good change to make anyway, but I'm not certain it will fix the problem you're seeing. If you wouldn't mind trying this out and letting me know, I'd appreciate it. Thanks!

  5. Fabio says:

    Hi David,

    thanks for your fast reply.

    i've tryed oot your suggestion but nothing changed. here the fragments:

    my xaml:

      <localcontrols:MenuButton x:Name="DropTermButton" Content="Drop" Padding="4,1" Margin="4,0,0,0" Command="localclasses:MyCommands.Drop">

                                   <localcontrols:MenuButton.ButtonMenuItemsSource>

                                       <MenuItem Header="Term only" Command="localclasses:MyCommands.DropTerm"  />

                                       <MenuItem Header="Term and narrowers" Command="localclasses:MyCommands.DropTermTree"  />

                                   </localcontrols:MenuButton.ButtonMenuItemsSource>

                               </localcontrols:MenuButton>

    generic.xaml:

      <ContextMenuService.ContextMenu>

                                   <ContextMenu ItemsSource="{Binding ButtonMenuItemsSource, RelativeSource={RelativeSource TemplatedParent}}" Foreground="{TemplateBinding Foreground}" FlowDirection="{TemplateBinding FlowDirection}" DataContext="{TemplateBinding DataContext}" />

                               </ContextMenuService.ContextMenu>

    thanks again

  6. David Anson says:

    Fabio,

    Two things to check:

    1. When you made that change to generic.xaml, did you do it for *both* SplitButton and MenuButton?

    2. Try removing the Command binding on MenuButton itself – I'm not sure what effect it would have, and it doesn't fit with my idea of how MenuButton should behave (always show the menu).

    If neither of those helps, could you please create a small, self-contained sample and send it to me via the "Email Blog Author" link? The answer may depend on something specific about your scenario that isn't true for my simple test case.

    Thanks!

  7. Fabio says:

    hi David, neither of your suggestions worked for me. i've packed up a very simple project that look like the more complex one. i've posted it to skydrive.

    here's the link:

    cid-3c018077b51a3ea8.office.live.com/…/MenuButtonSample.zip

    thanks in advance

    Fabio

  8. David Anson says:

    Fabio,

    Thank you – I'll try to have a look at your sample in the next couple of days and let you know what I find.

  9. David Anson says:

    Fabio,

    I've looked at this a bit just now and I can tell you WHY it's not working – though I don't yet know how to fix it. 😐 What you're seeing is similar to the DataContext issue I identified above – but things are different for your scenario because you're using RoutedCommands instead of Bindings to ICommand implementations. What seems to be the case in your example is that the ContextMenu for the SplitButton doesn't have the main Window instance as a logical ancestor – so the RoutedCommands you've hooked up to your MenuItems don't bubble all the way up to the handlers you've attached to the main Window instance. I find that if I call AddLogicalChild from the SplitButton's handler for ContextMenu.Opened to set the Popup parent of the ContextMenu as a logical child of the SplitButton instance, the CanExecute handlers you've defined suddenly start getting called like we want! However, once I've made that change, the ContextMenu suddencly starts dismissing itself immediately after opening… So this is progress, but not quite all the way to a working solution. I'll keep looking into this, but wanted to give you an update now that I knew something more. Thanks for your patience!

  10. Fabio says:

    David, thank you so much!

    Fabio

  11. David Anson says:

    Fabio,

    I think I have fixed the problem. 🙂 Could you please contact me via http://cesso.org/r/Email and I'll reply with the new code so you can try it out yourself? If you confirm the fix, I'll blog it in the next couple of days and credit you for the bug report.

    Thanks for your help!

  12. tmcconechy says:

    Hi,

    I read through the last few posts. Wondering if you have posted up any new code that will work with MVVM? I tried with:

      <common:IconButton IconImage="Save"  Command="{Binding OptionClick}" Height="22" HorizontalAlignment="Left"  Name="iconButton1" VerticalAlignment="Top" ToolTipService.ToolTip="Create New Row" >

                           <common:SplitButton.ButtonMenuItemsSource>

                           <toolkit:MenuItem Header="Option1" Command="{Binding OptionClick}"/>

                           <toolkit:MenuItem Header="Option2" />

                           <toolkit:MenuItem Header="Option3" />

                           </common:SplitButton.ButtonMenuItemsSource>

                       </common:IconButton>

    But it is not responding to my commands similar to the above…

    Thanks!

  13. David Anson says:

    tmcconechy,

    MVVM scenarios should already work. I'm guessing your Bindings aren't pointing where you want – please have a look at the Output window when running your application to see if there are any diagnostic messages about Bindings not hooking up right.

    Here's what I did to verify this on the latest SplitButton.zip with Silverlight 4, by the way:

    public class MyCommand : ICommand

    {

       public bool CanExecute(object parameter)

       {

           return true;

       }

       public event EventHandler CanExecuteChanged;

       public void Execute(object parameter)

       {

           MessageBox.Show("Executed");

       }

    }

    public MainPage()

    {

       InitializeComponent();

       DataContext = new MyCommand();

    }

    <splitButton:SplitButton Content="Open" Command="{Binding}">

       <splitButton:SplitButton.ButtonMenuItemsSource>

           <toolkit:MenuItem Header="Open" Command="{Binding}"/>

           <toolkit:MenuItem Header="Open read-only"  Command="{Binding}"/>

       </splitButton:SplitButton.ButtonMenuItemsSource>

    </splitButton:SplitButton>

    It worked as expected when I ran the modified sample. Hope this helps!

  14. Joey says:

    Great split button and thanks for the posts. Any thoughts on supporting toolkit themes?

  15. David Anson says:

    Joey,

    Thanks! I'm probably not going to do additional themes myself, but if someone did, I'd be happy to link to their work. 🙂

  16. John Langley says:

    David,

    I'm glad I found this control, very simple & easy to understand!  I want to expand upon tmcconechy's question & your answer regarding Commands.  I'm quite new to Silverlight but understand MVVM is a pattern worth learning, but I'm having difficulty understanding how you can determine which item was actually selected by the user?  Everything funnels into MyCommand::Execute and I'm not seeing any way to differentiate what triggered the event.  Thanks for any ideas / advice on what I might be missing.

  17. David Anson says:

    John Langley,

    Thanks for the compliments!

    When commanding, it's common to use a dedicated command implementation for each "function". For example, there might be a command for Printing and it will be hooked up to the File/Print option and a Toolbar button and the Ctrl+P accelerator – and because they're all supposed to print, it doesn't care which one triggered it – it just prints. 🙂 Where things get a little different is when you have a command in a ListBox for something like "remove" and all the items look the same. In this case, I might use the CommandParameter property to pass in some item-specific information that the command implementation can then use to determine which specific item needs to be dealt with.

    Hope this helps!

  18. Amaryllion says:

    Great SplitButton, the easiest I have seen so far.

    But I have a question regarding the MenuItem-part: I don't know my MenuItems in designtime so I cannot write them manual in xaml.

    So I thought about binding a ObservableCollection of MenuItems (including ICommands and all that stuff) from my ViewModel, because I hold all the Information in a Collection anyway. But how to do bind to the Button? ButtonMenuItemsSource is not suited for binding.

    I would be glad if you could help me with this! 🙂

    I have constant battles with all kind of SplitButtons for a while now and it seems that ContextMenus try to wear me down. 😉

  19. Amaryllion says:

    Oh, sorry, I was so stupid 🙂 Of course I just had to change ButtonMenuItemsSource into a DependencyProperty and everything is fine!

    Thank you for such a nice and easy-to-use control! 🙂

  20. David Anson says:

    Amaryllion,

    I'm glad you got that sorted out – I'm sorry for the trouble! In case it helps you feel better, making that very change is on my TODO list for a future release of SplitButton. 🙂

    PS – Thanks for the kind words!

  21. rlodina says:

    Hi David,

    Thank you for this control.

    I want to report a bug:

    The  SplitButton control paced in a ChildWindow – SL4 – strange behaviour: the drop down section is out of place.

    Any idea ?

    Thank you

  22. rlodina says:

    Hi – more info about:

     "The  SplitButton control paced in a ChildWindow – SL4 – strange behaviour: the drop down section is out of place.".

    The problem appear only if  Zoom Level (applied by IE) != 100 and SplitButton control paced in a ChildWindow;

  23. David Anson says:

    rlodina,

    I think I've heard of other issues with controls inside a ChildWindow at non-100% browser zoom levels. I haven't looked into this specifically, but my guess would be that something about ChildWindow affects how otherwise correctly-functioning controls operate (possibly the Popup or the centering mechanism?). If someone can identify why that is, it might help here…

  24. Kyle says:

    this is a great set of extensions.  Could you point me in the right direction to find what I need to update in the templates to have the control toolkit's styles picked up in these controls?

  25. David Anson says:

    Kyle,

    Thanks! 🙂 Unfortunately, the templating story for XAML doesn't make this task as easy as it could be. Basically, each theme's template contains a complete definition of the control's UI, so if you want to create a SplitButton using the "Whistler Blue" theme (or whatever), you'll need to start from the Button template for that theme. Fortunately, those templates are available via Blend's Edit Template feature or in source form as part of the Silverlight Toolkit download. The steps to customize a Button template for for SplitButton are quite simple – I outlined them in the original post: blogs.msdn.com/…/developer-test-case-customer-win-using-contextmenu-to-implement-splitbutton-and-menubutton-for-silverlight-or-wpf.aspx

    Hope this helps!

  26. Mark says:

    I found that the contextmenu offset was still wrong when the split button was on a childwindow.  I added the following scaling which seems to have fixed it:

               _contextMenu.HorizontalOffset = ( desiredOffset.X – currentOffset.X ) * Application.Current.Host.Content.ZoomFactor;

               _contextMenu.VerticalOffset   = ( desiredOffset.Y – currentOffset.Y ) * Application.Current.Host.Content.ZoomFactor;

  27. David Anson says:

    Mark,

    That's great, thank you for sharing! 🙂

  28. Migus says:

    Hi David,

    tried your sample in SL5 and the context menu position is not displayed under the button anymore.

    Do you have a sample working for SL5?

    Thanks.

  29. David Anson says:

    Migus,

    Sorry, I don't have a Silverlight 5 version handy. 🙁 If you find out what's broken with that platform and are able to follow-up here, that would be much appreciated!

  30. Chevon says:

    Hey David,

    I am using the SplitButton in a WPF .NET 4.0 application (it is the child of a  stackpanel in a window). For some reason, the context menu  (without any interaction) initially pops up in the top right corner of my primary monitor when the window is instantiated. It disappears after a couple seconds then all is well. Any idea why this occurs?

    -Thanks. Great blog by the way! I am also utilizing your VirtualFile stuff for Drag and Dropping to windows 🙂

  31. David Anson says:

    Chevon,

    I'm not sure why that should happen… You might try setting a couple of breakpoints to see if the code to show the ContextMenu is getting triggered somehow. I don't recall that being a problem with the sample application, so maybe it has something to do with how your app is structured?

    PS – Thanks for the kind words! 🙂

Comments are closed.