Search code examples
c#wpfxamlmvvmviewmodel

Unable to get values from pop up window in parent view model WPF MVVM application


I am trying to access property value of a child window's view model from the parent View Model.I am calling window from parent view model.I want to make changes in main window based on the operation in child view model. I couldn't get any value of child view model in parent view model.I am trying this in MVVM pattern.

Interface for dialog

 public interface IWindowService
{
    void OpenDialogWindow(DialogViewModel vm);
     
}

Parent view model

 public class FunctionalViewModel : INotifyPropertyChanged
    {
private readonly IWindowService _windowService;
 private string connectionString;

        public string ConnectionString
        {
            get { return connectionString; }
            set
            {
                connectionString = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ConnectionString"));
            }
        }
 public FunctionalViewModel(IWindowService windowService)
        {
           BuildConnectionCommand = new RelayCommand(new Action<object>(BuildConnectionString));
            _windowService = windowService;
        }
   private void BuildConnectionString(object obj)
        {
            MessageBox.Show("will open a window");
            _windowService.OpenDialogWindow(new DialogViewModel());                                  

        }
}

Child View Model

public class DialogViewModel : FunctionalViewModel,INotifyPropertyChanged
    {
        private string textboxsaf;

        public string Textboxsaf
        {
            get { return textboxsaf; }
            set {
                textboxsaf = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Textboxsaf"));
            }
        }

        private ICommand connectionCommand;

        public ICommand ConnectionCommand
        {
            get { return connectionCommand; }
            set { connectionCommand = value; }

        }
        public DialogViewModel()
        {
            
            ConnectionCommand = new RelayCommand(new Action<object>(SetValue));
            

        }
        public event PropertyChangedEventHandler PropertyChanged;


        public void SetValue(object test)
        {
            textboxsaf= "ValueFromPopUpWindo";           
            Application.Current.Windows[1].Close();
            
        }
     

        }

ChildWindow.xaml

    <Grid>
        <Label x:Name="label" Content="my popup window" HorizontalAlignment="Left" Margin="73,68,0,0" VerticalAlignment="Top" Width="132"/>
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="73,121,0,0" 
                 TextWrapping="Wrap" 
                 Text="{Binding Path=Textboxsaf,Mode=TwoWay}" VerticalAlignment="Top" Width="120"/>
        <Button x:Name="button" Content="Button" HorizontalAlignment="Left"
                Margin="109,177,0,0" VerticalAlignment="Top" Width="75"
                 Command="{Binding Path=ConnectionCommand }"
                 />

    </Grid>
</Window>

MainWindow.xaml

<Grid>
 <Button Name="btnConnectionString" Grid.Row="0" Grid.Column="2" Content="Connection string" Height="40" Width="150"
                                 Command="{Binding Path=BuildConnectionCommand}"
                                        DataContext="{Binding tfs}"></Button>
</Grid>

Code behind file of main window MainWindow.xaml.cs

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainViewModel()
            {
                rel = new ReleaseViewModel(),
                tfs =  new FunctionalViewModel(new WindowService()),
                wnd = new DialogViewModel()
            };

        }

  
    }
    public class WindowService : IWindowService
    {
        public void OpenDialogWindow(DialogViewModel vm)
        {
            ConnectionWindow win = new ConnectionWindow();
            win.DataContext = vm;            
            win.Show();            
        }               
    }

Question

I would like to access the value of the property Textboxsaf in the child view model(DialogViewModel) from parent view model(FunctionalViewModel) . Assign value of Textboxsaf to ConnectionString from the funcitonalviewModel . after closing window is good.


Solution

  • I wouldn't use PropertyChanged to retrieve the value of DialogViewModel.Textboxsaf as this proprty might change multiple times during the lifetime of the dialog.

    I would make IWindowService.OpenDialogWindow return a custom DialogResult object or the original DialogViewModel probably converting the IWindowService.OpenDialogWindow to an asynchronous method.

    Alternatively implement a IWindowService.DialogClosed event:

    FunctionalViewModel.cs

    public class FunctionalViewModel : INotifyPropertyChanged
    {
        private readonly IWindowService _windowService;
        private string connectionString;
    
        public string ConnectionString
        {
            get { return connectionString; }
            set
            {
                connectionString = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.ConnectionString)));
            }
        }
    
        private void BuildConnectionString(object obj)
        {
            MessageBox.Show("will open a window");
            _windowService.DialogClosed += OnDialogClosed;
            _windowService.OpenDialogWindow(new DialogViewModel());                                  
        }
    
        private void OnDialogClosed(object sender,  DialogResultEventArgs e)
        {
            _windowService.DialogClosed -= OnDialogClosed;
            ConnectionString = e.Result.Textboxsaf;
        }
    }
    

    WindowService.cs

    public class WindowService : IWindowService
    {
        public event EventHandler<DialogResultEventArgs> DialogClosed;
        public void OpenDialogWindow(DialogViewModel vm)
        {
            ConnectionWindow win = new ConnectionWindow();
            win.DataContext = vm;
            win.Closed += OnConnectionWindowClosed;
            win.Show();            
        } 
              
        protected virtual void OnConnectionWindowClosed(object sender, EventArgs e)
        {
            var dialog = sender as FrameworkElement;
            this.DialogClosed?.Invoke(this, new DialogResultEventArgs(dialog.DataContext as DialogViewModel));
        }               
    }
    

    DialogResultEventArgs.cs

    public class DialogResultEventArgs : EventArgs
    {
        public DialogViewModel Result { get; }
              
        public DialogResultEventArgs(DialogViewModel result) => this.Result = result;
    }