Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a MultiSelectionComboBox #4006

Merged
merged 23 commits into from
Oct 22, 2021

Conversation

timunie
Copy link
Collaborator

@timunie timunie commented Dec 15, 2020

Describe the changes you have made to improve this project

Added a MultiSelectionComboBox- Control which can be used to let the user select several items.

  • Can be editable or readonly
  • You can select a Separator
  • You can select a SelectionMode like in a ListBox

Unit test

None

Additional context

See also #4000 and #3802

image
See it in Action

Please give me any feedback on this control.

Closed Issues

Closes #3802

@timunie

This comment has been minimized.

@timunie timunie force-pushed the feature/MultiSelectionComboBox branch from 917d53f to 81822a5 Compare December 21, 2020 07:25
@timunie

This comment has been minimized.

@Luk164
Copy link

Luk164 commented Dec 27, 2020

May it be a good idea to add ListView or even a DataGrid in the PopUp? ListView would add the possibility to have a more unfriendly PopUp and DataGrid would allow to add your own Items to the ItemSource.

I don't think there is any need for those right now, but they can always be added later. RN I would go with your current implementation and see how well it works out.

@timunie

This comment has been minimized.

@Luk164
Copy link

Luk164 commented Dec 28, 2020

@timunie TBH what I need is a tool where I can put a list of all choices and get out a list of the ones user ticked. As long as that can be done I am fine with whatever way you achieved it.

@timunie timunie changed the title [WIP][RFC] Implement a MultiSelectionComboBox [RFC] Implement a MultiSelectionComboBox Jan 7, 2021
@timunie
Copy link
Collaborator Author

timunie commented Jan 8, 2021

Hi @Luk164 , @punker76 , @ExLuzZziVo and anyone else interested:

For my usecase I am now quite happy with the control. I would be very happy to get your feedback as well. You can try the control if you clone my branch and run the DemoApp.

MultiSelectionComboBox_Example.mp4

@punker76 I will update the Codacy-issues later. Also I want to wait until #4009 from @batzen is merged.

Happy coding and a great weekend all of you
Tim

@timunie timunie force-pushed the feature/MultiSelectionComboBox branch from 9303b1c to 6665884 Compare January 9, 2021 18:33
@timunie
Copy link
Collaborator Author

timunie commented Jan 13, 2021

There is a new issue which we should remember to add to the documentation: timunie/TimsWpfControls#14 (comment)

Thank you @GWawrzeniecki for finding this.

@punker76 maybe you have an idea if we can load to the Popup before it is actually opened?

@nalka0
Copy link

nalka0 commented May 4, 2021

Instead of having the MultiSelectionComboBox.StringToObjectParser DependencyProperty, wouldn't it be better to make the conversion (MultiSelectionComboBox.cs:723) through the default TypeConverter for the good object type?

@timunie

This comment has been minimized.

@nalka0
Copy link

nalka0 commented May 5, 2021

Hi @nalka0

thank you for this idea. At the moment I think I'll stick with the current implementation as it seems like this involves Reflexion which I try to avoid for performance reasons. Having the interface IParseStringToObject seems to be easy enough to implement.

Would it be an alternative for you if there is a build in StringToObjectParser which then may use the TypeConverter to provide the needed value?

Happy coding
Tim

Even though I don't think any user would notice some more milliseconds during the conversion of the new item he typed (so the performance aspect of this code is kind of irrelevant IMHO), using this implementation would also allow removing the StringToObjectParser dependency property and thus removing some Reflection (one less Binding).

Anyways, my approach here is to make the MSC (MultiSelectionComboBox) lighter for the developper who'll use it and to do things using the standard ways in order to reduce their code duplication. It may not be the best example but imagine someone wants to use your MSC with some System.Windows.Media.Brush, they would have to more or less copy what's in System.Windows.Media.BrushConverter.ConvertFrom(ITypeDescriptorContext, CultureInfo, object) and paste it in an IParseStringToObject implementation.

You proposed providing a built-in IParseStringToObject to wrap the TypeConverter, if you're going to stick with your implementation it looks like a good idea to me. Still, for all the reasons detailed above, I think always using the TypeConverter is better.

PS : I'm not that familiar with Github, are we in the good place to discuss this?

@timunie

This comment has been minimized.

@Luk164
Copy link

Luk164 commented May 6, 2021

@timunie Wow, you did quite some work on this. I really hope this gets released soon.

@timunie
Copy link
Collaborator Author

timunie commented May 6, 2021

Below is a list of still open points

  • add AddingItemEvent
  • add AddedItemEvent
  • reset text only if Textbox does not have Keyboard focus as this may irritate the user
  • check if we need the binding helper
  • Add Control over ▲ and ▼-Keys. Currently they select the next element which is not good in Multiselection mode.

@punker76 I could need some help / guide regarding these issues

  • Is there a way to use Binding to the IsSelected Property of the ListBoxItems? Seems like it is not triggered when drop-down is not open yet
  • Is there a way to bind to SelectedItems via the Helper which we already have? I was not able to get this to work yet.

@timunie timunie force-pushed the feature/MultiSelectionComboBox branch from e19b195 to 658c099 Compare May 12, 2021 14:36
@FroggieFrog
Copy link
Contributor

I played around with the control and have some feedback:

  • First of all: Excellent work! 👍
  • For my use case an option to add an "Select All" element would be really helpful.
    The Extended WPF Toolkit has a similiar control and has two properties for that IsSelectAllActive and SelectAllContent (see wiki page)
  • How can I get the following behavior?
    • Result should look like Text -> switch IsEditable to On
    • User is not able to edit by entering characters -> switch IsReadOnly to On
    • User clicks on ComboBox and Dropdown should open (just like when IsEditable is Off) -> How? It only opens by clicking the arrow.

multiselectioncombobox_opendropdown

@timunie
Copy link
Collaborator Author

timunie commented Jul 1, 2021

Hi @FroggieFrog

thank you for your feedback. Below please find some thoughts from my side:

For my use case an option to add an "Select All" element would be really helpful. [...]

Yes, I was also thinking of an option like this, but I want more. Maybe filtering, sorting, select all, select none, invert selection, add new item, what ever you can think of. So my idea is to add two ContentControls in the PopUp like this:

image

Then you can apply your style, your controls and your functions you like. Should not be too hard I guess. Let me know if this is a way for you as well.

How can I get the following behavior? [...] User clicks on ComboBox and Dropdown should open (just like when IsEditable is Off) -> How? It only opens by clicking the arrow.

I think this is not how a normal ComboBox works, so the MultiSelectionComboBox does not (try it in the Demo with a normal ComboBox). If the control is ReadOnly="True" and IsEditable="True" the use must still be able to select and copy the Text. If I capture the MouseDownEvent here to open the control this functionality is lost. So I think if you really need this, you will have to get the TextBox in code behind and listen to the PreviewMouseDown-Event as well as the GotFocus-Event.

// THE FOLLOWING CODE IS NOT PRODUCTION READY AND SHOULD ONLY SHOW THE BASIC CONECPT.
// Register to the loaded event of your MSCB
private void mscb_Example_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
    if (sender is MultiSelectionComboBox multiSelectionComboBox)
    {
        multiSelectionComboBox.ApplyTemplate(); // Make sure the Template is loaded.
        if (multiSelectionComboBox.FindChild<TextBox>("PART_EditableTextBox") is TextBox textBox) // Get the TextBox
        {
            textBox.GotFocus -= TextBox_GotFocus; 
            textBox.GotFocus += TextBox_GotFocus; 
        }
    }
}

// Do the opening here.
private void TextBox_GotFocus(object sender, System.Windows.RoutedEventArgs e)
{
    if (mscb_Example.IsReadOnly && mscb_Example.IsEditable)
    {
        mscb_Example.SetCurrentValue(ComboBox.IsDropDownOpenProperty, true);
        e.Handled = true;
    }
}

Happy coding
Tim

@punker76 punker76 force-pushed the feature/MultiSelectionComboBox branch from aff5bf1 to ddf9ea9 Compare July 7, 2021 11:56
Copy link

@Luk164 Luk164 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but I feel like we should add some automated tests later on, to make sure everything keeps working.

@punker76 punker76 force-pushed the feature/MultiSelectionComboBox branch from 18ec30b to baf6970 Compare October 21, 2021 13:37
@punker76 punker76 changed the title [RFC] Implement a MultiSelectionComboBox Implement a MultiSelectionComboBox Oct 21, 2021
@punker76 punker76 added this to the 3.0.0 milestone Oct 21, 2021
@punker76 punker76 force-pushed the feature/MultiSelectionComboBox branch from baf6970 to 87bf90f Compare October 21, 2021 20:11
timunie and others added 20 commits October 21, 2021 22:27
- Add ToString() for the sample data
- ClearTextButton
- AutoWatermark
- Ability to use custom PanelTemplate
- Add SelectedItemContainerStyle
- Add ScrollViewer
Update selection based on user defined text

- Add `IObjectToStringComparer`- Interface to detect the matching objects.
- Add possibility to control the `StringComparision`
to the `ItemsSource` (only if it implements `IList`.

Note: The user needs to implement the interface on his own as there are so many different use cases possible. We have an example implementation in the demo App.
- Add more options for Styling and use it with DataTemplate
- Added RightToLeft-Support
- Add SelectedItemStringFormat so one can set different formats for the Popup and the SelectedItem
- Respect SelectedItemStringFormat for the editable text as well
- Additionally update the `Text`when `SelecteItemStringFormat` or `Separator` changes.
This attached property was missing here, so the horizontal scrolling was not possible.
- Implement `mah:ScrollViewerHelper.IsHorizontalScrollWheelEnabled` to control weather the selection should be changed via mouse wheel or not.
- Also attachable to normal `ComboBox`
- Override `PreviewMouseWheel` to prevent selection change if wanted and scroll the content instead
- Selection via mouse wheel can only work if the selection mode is `Single`.
Additionally make these minor improvements

- make Command fully static 
- restore selection after clear text
- better check if ItemsSource is in use (PopupListBox)

Changes from review
- We need to override the `SelectedIndex` and `SelectedItem` because the normal `ComboBox` behaves differently here. 
Remove not needed for-loop
It uses internally a `TypeConverter` to convert the string to the given `Type`.
- new AddingItemEvent
- new AddedItemEvent
- Fix typos
- less user disturbtion

Improve Selection from MouseWheel and Keyboard

- only allow those selections when in `SelectionMode.Single`
- Let the developer choose if this kind of selection is allowed

- Enable Binding to SelectedItems
- Fix MultiSelectorHelper
- Do not crash if new value is null. Instead do not apply the Binding
With this change the user can implement quite easy a select all /select none button or other header or footer content
@punker76 punker76 force-pushed the feature/MultiSelectionComboBox branch from 87bf90f to 4807b02 Compare October 21, 2021 20:28
@punker76 punker76 merged commit f024a8a into MahApps:develop Oct 22, 2021
@punker76
Copy link
Member

@timunie your changes have been merged, thanks for your contribution 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging this pull request may close these issues.

Multi-select combo box with check marks
6 participants