RWS / Multiselect-ComboBox

The multi selection combo box is a WPF custom control with multiple item selection capabilities, along with customizable features to group, sort and filter items in the collection.
Apache License 2.0
182 stars 55 forks source link

Multiselect-ComboBox in a modal dialog #5

Closed p0ria closed 5 years ago

p0ria commented 5 years ago

Hi, Thanks for your useful control. This control does not work in a modal dialog. The ItemsSource property is always empty.

Impertatore commented 5 years ago

Hi @p0ria, can you please provide an example so I can understand better what problem you are facing with setting the ItemSource binding? send to phartnett@sdl.com

p0ria commented 5 years ago

Here is my sample:

 public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void ButtonShowModalWindow_OnClick(object sender, RoutedEventArgs e)
        {
            var dlg = new ModalWindow();
            dlg.DataContext = new ModalWindowVM();
            dlg.Show();
        }
    }

    public class ModalWindowVM : INotifyPropertyChanged
    {
        private ObservableCollection<Person> people;

        public ModalWindowVM()
        {
            People = new ObservableCollection<Person>
            {
                new Person{Id = 1, Name = "Pooria"},
                new Person{Id = 2, Name = "Ahmad"}
            };
        }

        public ObservableCollection<Person> People
        {
            get { return people; }
            set
            {
                people = value;
                OnPropertyChanged();
            }
        }

        private List<Person> _selectedPeople = new List<Person>();

        public IEnumerable<Person> SelectedPeople
        {
            get { return _selectedPeople; }
            set
            {
                _selectedPeople = new List<Person>(value);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
p0ria commented 5 years ago

And here is my Modal Window xaml file

<Window x:Class="ModalWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp6"
        xmlns:sdl="http://schemas.sdl.com/xaml"
        mc:Ignorable="d"
        Title="PopupWindow" Height="450" Width="800">
    <Window.Resources>
        <DataTemplate x:Key="MultiSelectComboBoxDropDownItemTemplate" DataType="local:Person">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="50" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>

                <TextBlock Text="{Binding Path=Id}" />
                <TextBlock Grid.Column="1" Text="{Binding Path=Name}" Margin="5 0 0 0" />
            </Grid>
        </DataTemplate>
        <DataTemplate x:Key="MultiSelectComboBoxSelectedItemTemplate" DataType="local:Person">
            <TextBlock Text="{Binding Path=Name}" Margin="2,0" />
        </DataTemplate>
    </Window.Resources>
    <StackPanel x:Name="Panel">
        <sdl:MultiSelectComboBox x:Name="cmbox"
                                 Margin="3"
                                 Height="50"
                                 DropdownItemTemplate="{StaticResource MultiSelectComboBoxDropDownItemTemplate}"
                                 SelectedItemTemplate="{StaticResource MultiSelectComboBoxSelectedItemTemplate}"
                                 IsEditable="True"
                                 SelectedItems="{Binding SelectedPeople}"
                                 ItemsSource="{Binding Path=People, Mode=OneWay}" />
        <Button  Click="ButtonBase_OnClick">Press</Button>
    </StackPanel>
</Window>
p0ria commented 5 years ago

I create an instance of ModalWindow class, set its DataContext property and Show() it. But when the ModalWindow opens, the inner MultiSelectComboBox is empty... I tested it in MainWindow (MultiSelectComboBox inside MainWindow instead of ModalWindow) and it worked, but it does not work inside ModalWindow.

Impertatore commented 5 years ago

Hi @p0ria, please make the following changes and confirm again:

  1. dlg.DataContext = new ModalWindowVM();

  2. public ObservableCollection People { get { return people; } set { people = value; OnPropertyChanged(nameof(People)); } }

p0ria commented 5 years ago

I did it does not work yet. Can you please test it?

Impertatore commented 5 years ago

Hi @p0ria, yes I have tested and did not see any problems.

I have uploaded a simple example project, taking into consideration your example code above. The project is located here.

It demonstrates loading the view (as a model window) after setting the data context without any issues. Please download the project, review it and confirm that you can run/debug it on your computer + that it represents a working solution of the issue that you are describing.

If for some reason the project that I have provided you does not represent what you are describing, then I would ask you to please send me the solution (or an extract of it) that you working on so that I can have more context to reproducing.

p0ria commented 5 years ago

hi @Impertatore, yes your sample works, but my problem is when a window makes a modal window. I mean this one:

public partial class ExampleView : Window
    {
        public ExampleView()
        {
            InitializeComponent();
        }

        private void ButtonPress_OnClick(object sender, RoutedEventArgs e)
        {
            // Instantiate window
            var view2 = new View.ExampleView();

            // Instantiate model
            var model = new ExampleViewModel();

            // assign the data context
            view2.DataContext = model;

            // show window modally
            view2.ShowDialog();

        }
    }

I also uploaded my solution here. When you click on press button, the MultiselectComboBox inside the new Modal Window is not populated.

Impertatore commented 5 years ago

Hi @p0ria, Thank you for providing more context with the example code. It is not possible to achieve the result that you are expecting in this case, as the data tree doesn't exist yet. In this case you should assign the data context after the view has loaded.

I have included a working example here: MultiComboBoxDemo102_updated.zip

example: ` public partial class SettingsView : Window { private readonly SettingsViewModel _model;

public SettingsView(SettingsViewModel model)
{
    _model = model;

    InitializeComponent();

    Loaded += SettingsView_Loaded;
}

private void SettingsView_Loaded(object sender, RoutedEventArgs e)
{
    Loaded -= SettingsView_Loaded;

    DataContext = _model;
}

}`

p0ria commented 5 years ago

Hi @Impertatore. Yes It works this way. Thank you so much for your patient and answer.