Search code examples
wpfmvvmcomboboxviewmodelselectionchanged

WPF MVVM Combobox SelectionChanged just after reload the ViewModel


My problem is, after the SelectionChanged event nothing happen. The TextBox didnt get any new value relaited to the ComboBox. When I reload the ViewModel (Go page 1 and back), the TexBox has his new value relaited to the ComboBox.

Below you can see what I have on till now.

View:

<StackPanel Orientation="Vertical" Grid.Row="1">
                    <Border Width="150" Height="150" CornerRadius="80" BorderThickness="1" BorderBrush="Gray" HorizontalAlignment="Center">
                        <Border.Background>
                            <ImageBrush ImageSource="/Assets/FEBSolution.png"/>
                        </Border.Background>
                    </Border>

                    <TextBlock x:Name="EmployerName" Text="{Binding EmployerName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" Margin="0 10 0 0" FontWeight="Bold"/>
                    <TextBlock x:Name="EmpDescription" Text="{Binding EmpDescription, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="11" HorizontalAlignment="Center" Opacity="0.8"/>
                    <TextBlock x:Name="EmpMotto" Text="{Binding EmpMotto, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="8" HorizontalAlignment="Center" Opacity="0.8"/>

                    <StackPanel Margin="20">
                        <StackPanel Orientation="Horizontal" Margin="0 3" HorizontalAlignment="Left">
                            <materialDesign:PackIcon Kind="Location" />
                            <TextBlock x:Name="EmpLocation" Text="{Binding EmpLocation, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="10 0"/>
                        </StackPanel>

                        <StackPanel Orientation="Horizontal" Margin="0 3" HorizontalAlignment="Left">
                            <materialDesign:PackIcon Kind="Phone" />
                            <TextBlock x:Name="EmpPhone" Text="{Binding EmpPhone, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="10 0"/>
                        </StackPanel>

                        <StackPanel Orientation="Horizontal" Margin="0 3" HorizontalAlignment="Left">
                            <materialDesign:PackIcon Kind="Email" />
                            <TextBlock x:Name="EmpEmail" Text="{Binding EmpEmail, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"  Margin="10 0"/>
                        </StackPanel>
                    </StackPanel>
                </StackPanel>

                <ComboBox x:Name="cmbEmployer" Grid.Row="2" SelectedValuePath="ID" SelectedValue="{Binding ID}" ItemsSource="{Binding contractDetails}" SelectedItem="{Binding ContractSelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="EmployerName" materialDesign:HintAssist.Hint="Employer" Width="200" HorizontalAlignment="Center" Margin="10">
                    <ie:Interaction.Triggers>
                        <ie:EventTrigger EventName="SelectionChanged">
                            <ie:InvokeCommandAction Command="{Binding SelectionChangedCommand, UpdateSourceTrigger=PropertyChanged}"  CommandParameter="{Binding ElementName=cmbEmployer, Path=SelectedItem}"/>
                        </ie:EventTrigger>
                    </ie:Interaction.Triggers>
                </ComboBox>

ViewModel:

private ContractDetail _contractSelectedItem;
    public ContractDetail ContractSelectedItem
    {
        get { return _contractSelectedItem; }
        set 
        { 
            _contractSelectedItem = value;
            EmployerName = _contractSelectedItem.EmployerName;
            EmpDescription = _contractSelectedItem.EmpDescription;
            EmpMotto = _contractSelectedItem.EmpMotto;
            EmpLocation = _contractSelectedItem.EmpLocation;
            EmpPhone = _contractSelectedItem.EmpPhone;
            EmpEmail = _contractSelectedItem.EmpEmail;
            OnPropertyChanged(nameof(ContractSelectedItem)); 
        }
    }

    public List<ContractDetail> contractDetails { get; set; }

    #region Public all Commands
    //Command for change User 
    public ICommand ChangeUserCommand { get; private set; }
    public ICommand CloseWindowCommand { get; private set; }
    public ICommand SelectionChangedCommand { get; private set; }


    #endregion

    //PRWContext for general use
    private PRWContext context = new PRWContext();

    public ApplicationSettingViewModel()
    {
        // Load the data from PRW Database
        LoadUserData();
        BindContractComboBox();

        //Commands
        ChangeUserCommand = new RelayCommand(() => ExecuteChangeUserCommand());
        CloseWindowCommand = new RelayCommand(() => ExecuteCloseWindowCommand());
        SelectionChangedCommand = new RelayCommand(() => ExecuteSelectionChangedCommand());
    }

    private void ExecuteCloseWindowCommand()
    {
        foreach (Window window in Application.Current.Windows)
        {
            if (window is ApplicationSettingWindow)
            {
                window.Close();
                break;
            }
        }
    }

    private void ExecuteChangeUserCommand()
    {
        UserSettingWindow view = new UserSettingWindow();
        view.Show();
        foreach (Window window in Application.Current.Windows)
        {
            if (window is ApplicationSettingWindow)
            {
                window.Close();
                break;
            }
        }
    }

    private void ExecuteSelectionChangedCommand()
    {
        var item = context.ContractDetails.ToList();
        contractDetails = item;
    }
    //Load the user data 
    private void LoadUserData()
    {
        UserName = Settings.Default["UserName"].ToString();
        JobDescription = Settings.Default["UsrJobDescription"].ToString();
        Motto = Settings.Default["UsrMotto"].ToString();
        Street = Settings.Default["UsrStreet"].ToString();
        City = Settings.Default["UsrCity"].ToString();
        Country = Settings.Default["UsrCountry"].ToString();
        PhoneNumber = Settings.Default["UsrPhoneNumber"].ToString();
        Email = Settings.Default["UsrEmail"].ToString();
    }

    private void BindContractComboBox()
    {

        var item = context.ContractDetails.ToList();
        contractDetails = item;
    }

    #region PropertyChanged EventHandler
    //propertychanged eventhandler
    public event PropertyChangedEventHandler PropertyChanged;

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

For sure there is somthing missing, otherwise it will do the magic ;) I just dont know where i miss something. Any help will be welcome.


Solution

  • You aren't calling the OnPropertyChanged() for EmployerName, EmpDescription, EmpMotto, EmpLocation, EmpPhone, EmpEmail

    that's why your view doesn't get updated, and why are you actually using these separate properties when you can just use the ContractSelectedItem directly. You can access the nested properties like this "ContractSelectedItem.EmployerName"

    Try this in your viewmodel

    private ContractDetail _contractSelectedItem;
    public ContractDetail ContractSelectedItem
    {
        get { return _contractSelectedItem; }
        set 
        { 
            _contractSelectedItem = value;
            OnPropertyChanged(nameof(ContractSelectedItem)); 
        }
    }
    

    and change your view's binding like this

    <StackPanel Orientation="Vertical" Grid.Row="1">
                    <Border Width="150" Height="150" CornerRadius="80" BorderThickness="1" BorderBrush="Gray" HorizontalAlignment="Center">
                        <Border.Background>
                            <ImageBrush ImageSource="/Assets/FEBSolution.png"/>
                        </Border.Background>
                    </Border>
    
                    <TextBlock x:Name="EmployerName" Text="{Binding ContractSelectedItem.EmployerName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" Margin="0 10 0 0" FontWeight="Bold"/>
                    <TextBlock x:Name="EmpDescription" Text="{Binding ContractSelectedItem.EmpDescription, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="11" HorizontalAlignment="Center" Opacity="0.8"/>
                    <TextBlock x:Name="EmpMotto" Text="{Binding ContractSelectedItem.EmpMotto, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="8" HorizontalAlignment="Center" Opacity="0.8"/>
    
                    <StackPanel Margin="20">
                        <StackPanel Orientation="Horizontal" Margin="0 3" HorizontalAlignment="Left">
                            <materialDesign:PackIcon Kind="Location" />
                            <TextBlock x:Name="EmpLocation" Text="{Binding ContractSelectedItem.EmpLocation, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="10 0"/>
                        </StackPanel>
    
                        <StackPanel Orientation="Horizontal" Margin="0 3" HorizontalAlignment="Left">
                            <materialDesign:PackIcon Kind="Phone" />
                            <TextBlock x:Name="EmpPhone" Text="{Binding ContractSelectedItem.EmpPhone, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="10 0"/>
                        </StackPanel>
    
                        <StackPanel Orientation="Horizontal" Margin="0 3" HorizontalAlignment="Left">
                            <materialDesign:PackIcon Kind="Email" />
                            <TextBlock x:Name="EmpEmail" Text="{Binding ContractSelectedItem.EmpEmail, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"  Margin="10 0"/>
                        </StackPanel>
                    </StackPanel>
                </StackPanel>
    
                <ComboBox x:Name="cmbEmployer" Grid.Row="2" SelectedValuePath="ID" SelectedValue="{Binding ID}" ItemsSource="{Binding contractDetails}" SelectedItem="{Binding ContractSelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="EmployerName" materialDesign:HintAssist.Hint="Employer" Width="200" HorizontalAlignment="Center" Margin="10">
                    <ie:Interaction.Triggers>
                        <ie:EventTrigger EventName="SelectionChanged">
                            <ie:InvokeCommandAction Command="{Binding SelectionChangedCommand, UpdateSourceTrigger=PropertyChanged}"  CommandParameter="{Binding ElementName=cmbEmployer, Path=SelectedItem}"/>
                        </ie:EventTrigger>
                    </ie:Interaction.Triggers>
                </ComboBox>
    

    Also, there doesn't seem a reason to use the SelectionChanged event when you are just repopulating the contractDetails property every time the selection changes. Try to remove it if you aren't doing anything other then just repopulating the property.