Set Command.Parameter1 in Button1Command and use the value of the Command.Parameter1 in Button2Command returns null

130 Views Asked by At

I have two button commands. Let's call them BrowseButton1 and LoadButton1. The first command browses a file path (MVVM object) and sets this to a local path of my machine. Then the second ICommand (a.k.a LoadButton1) uses that file path (same MVVM object) to load some data to an SQL table.

My problem is that I cannot use the value of the file path in the second ICommand, because it is returned null

XAML code

<Window x:Class="TestEnvironment.MainWIndowTestStackOverflow"
        x:Name="MainWindowTestStackOverflow"
        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:TestEnvironment"
        mc:Ignorable="d"
        Height="720"
        Width="1145"
        ResizeMode="NoResize"
        WindowStartupLocation="CenterScreen"
        BorderBrush="Black"
        BorderThickness="1.5,1.5,1.5,1.5"
        WindowStyle="None">
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    </Window.Resources>
    <Grid x:Name="GridMain"
         Width="1145"
         Background="White"
         HorizontalAlignment="Center"
         ShowGridLines="False" 
         Grid.Row="1">
        <!--Grid Columns-->
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0"/>
            <ColumnDefinition Width="195"/>
            <ColumnDefinition Width="295"/>
            <ColumnDefinition Width="650"/>
            <ColumnDefinition Width="0"/>
        </Grid.ColumnDefinitions>
        <!--Grid Rows-->
        <Grid.RowDefinitions>
            <RowDefinition Height="0"/>
            <RowDefinition Height="45"/>
            <RowDefinition Height="45"/>
            <RowDefinition Height="45"/>
            <RowDefinition Height="45"/>
            <RowDefinition Height="52"/>
            <RowDefinition Height="400"/>
        </Grid.RowDefinitions>
        <TextBox
            Name="FileNameTextBox"
            Text="{Binding Path=FilesFilePath}"
            HorizontalAlignment="Left"
            VerticalAlignment="Center"
            Margin="5,0,0,0"
            IsReadOnly="True"
            FontStyle="Italic"
            FontFamily="Arial"
            FontSize="9"
            BorderThickness="0"
            Grid.Column="2"
            Grid.Row="1"/>
        <!--Apply ICommand to browse file 1st time-->
        <Button 
            x:Name="BrowseButton1"
            Content="Browse"
            Command="{Binding Path=BrowseButtonCommand}"
            IsEnabled="{Binding Path=EnableFilesBrowseButton, Converter={StaticResource BooleanToVisibilityConverter}}"
            HorizontalAlignment="Left"
            VerticalAlignment="Center"
            Width="80" 
            Height="25"
            Margin="40,0,0,0"
            Padding="0"
            FontWeight="Light"
            FontSize="10"
            Grid.Column="3"
            Grid.Row="1"
            Cursor="Hand">
            <Button.CommandParameter>
                <MultiBinding>
                    <MultiBinding.Converter>
                        <local:BrowseButtonConverter/>
                    </MultiBinding.Converter>
                    <Binding Path="FilesFilePath"/> //this is the value I want to exchange between the two ICommands
                    <Binding Path="EnableFilesBrowseButton"/>
                    <Binding Path="EnableFilesLoadButton"/>
                    <Binding Path="EnableFilesViewButton"/>
                    <Binding Path="FilesPanelVisibility"/>
                </MultiBinding>
            </Button.CommandParameter>
        </Button>
        <Button 
            x:Name="LoadButton1"
            Content="Load"
            Command="{Binding Path=LoadButtonCommand}"
            IsEnabled="{Binding Path=EnableFilesLoadButton, Converter={StaticResource BooleanToVisibilityConverter}}"
            Focusable="False"
            Width="80"
            Height="25"
            Margin="135,0,0,0"
            FontSize="10"
            FontWeight="Light"
            HorizontalAlignment="Left"
            VerticalAlignment="Center"
            Grid.Column="3"
            Grid.Row="1"
            Cursor="Hand">
           <Button.CommandParameter>
                <MultiBinding>
                    <MultiBinding.Converter>
                        <local:LoadButtonConverter/>
                    </MultiBinding.Converter>
                    <Binding Path="FilesFilePath"/> //this returns null even though browse button return the FilesFilePath
                </MultiBinding>
            </Button.CommandParameter>
        </Button>
    </Grid>
</Window>

.cs file

namespace TestEnvironment
{
    //Command parameters -Browse Button
    public class BrowseButtonCommandParameters
    {
        public string FilePathSelected { get; set; } //parameter 1
        public bool EnableBrowseButton { get; set; } //parameter 2
        public bool EnableLoadButton { get; set; } //parameter 3
    }
    //Browse - MultiValueConverter
    class BrowseButtonConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            // Error handling omitted for brevity
            // Casting omitted because question's code has insufficient context
            return new BrowseButtonCommandParameters
            {
                FilePathSelected = (string)values[0],
                EnableBrowseButton = (bool)values[1],
                EnableLoadButton = (bool)values[2],
            };
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException("to-source binding mode not supported");
        }
        private static BrowseButtonConverter _converter = null;

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (_converter == null) _converter = new BrowseButtonConverter();
            return _converter;
        }

        public BrowseButtonConverter()
            : base()
        {
        }
    }

    //Command parameters -Load Button
    public class LoadButtonCommandParameters
    {
        public string FilePathSelected { get; set; } //parameter 1
    }
    //Load - MultiValueConverter
    class LoadButtonConverter : MarkupExtension, IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            // Error handling omitted for brevity
            // Casting omitted because question's code has insufficient context
            return new LoadButtonCommandParameters
            {
                FilePathSelected = (string)values[0], //this is actually the FilePath defined from Browse Command.
            };
        }
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException("to-source binding mode not supported");
        }

        private static LoadButtonConverter _converter = null;

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (_converter == null) _converter = new LoadButtonConverter();
            return _converter;
        }

        public LoadButtonConverter()
            : base()
        {
        }
    }

    //----------------------------------------------------------------------------------------------------
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        //MVVM objects bound to XAML objects and connected to ICommand parameters

        //Used by BrowseButton1
        //1.
        private bool _enableFilesLoadButton;
        public bool EnableFilesLoadButton
        {
            get
            {
                return _enableFilesLoadButton;
            }
            set
            {
                _enableFilesLoadButton = value;
                OnPropertyChanged("EnableFilesLoadButton");
            }
        }

        //2.
        private bool _enableFilesBrowseButton;
        public bool EnableFilesBrowseButton
        {
            get
            {
                return _enableFilesBrowseButton;
            }
            set
            {
                _enableFilesBrowseButton = value;
                OnPropertyChanged("EnableFilesBrowseButton");
            }
        }

        //3.
        private string _FilesFilePath;
        public string FilesFilePath
        {
            get
            {
                return _FilesFilePath;
            }
            set
            {
                _FilesFilePath = value;
                OnPropertyChanged("FilesFilePath");
            }
        }

        //----------------------------------------------------------------------------------------------------
        //ICommand: BrowseButtonCommand
        public ICommand BrowseButtonCommand
        {
            get { return new DelegateCommand<object>(FuncBrowseCommand); }
        }
        public void FuncBrowseCommand(object parameters)
        {
            var param = (BrowseButtonCommandParameters)parameters;

            Nullable<bool> browse_result = BrowseFile(param.FilePathSelected); //command parameter 1, FilesFilePath
            Debug.WriteLine("FilesFilePath " + FilesFilePath);

            //Load button gets instantly disabled when every time the user clicks the Browse Button 
            param.EnableLoadButton = false; //command parameter 2
            Debug.WriteLine("EnableLoadButton: " + EnableFilesLoadButton);

            //Browse file
            if (browse_result == true)
            {
                param.EnableLoadButton = true; //command parameter 2
                Debug.WriteLine("EnableLoadButton: " + EnableFilesLoadButton);

                param.EnableBrowseButton = true; //command parameter 3
                Debug.WriteLine("EnableBrowseButton: " + EnableFilesBrowseButton);
            }
            else
            {
                return;
            }
        }

        public void FuncLoadButton(object parameters)
        {
            var param = (LoadButtonCommandParameters)parameters;
            Debug.Writeline("FilePath: "+ param.FilePathSelected); //this returns null
        }

        //Browse function used in Browse ICommand
        public bool BrowseFile(string filepathselected)
        {
            // Create OpenFileDialog
            OpenFileDialog openFileDlg = new OpenFileDialog();

            // Launch OpenFileDialog by calling ShowDialog method
            Nullable<bool> result = openFileDlg.ShowDialog();
            Debug.WriteLine("1. browse window result: " + result);

            // Set filter for file extension and default file extension  
            openFileDlg.DefaultExt = ".csv";
            openFileDlg.Filter = "All files (*.*)|*.*|CSV file (*.csv)|*.csv|Text files (*.txt)|*.txt";

            // Set initial directory
            openFileDlg.InitialDirectory = @"C:\Documents\";
            openFileDlg.Title = "Browse Files";

            openFileDlg.CheckFileExists = true;
            openFileDlg.CheckPathExists = true;
            openFileDlg.RestoreDirectory = true;

            // Multiple selection with all file types
            openFileDlg.Multiselect = true;

            // Get the selected file name and display in a TextBox.
            // Load content of file in a TextBlock
            if (result == true)
            {
                filepathselected = openFileDlg.FileName;
                Debug.WriteLine("2. File Path: " + filepathselected);
            }
            return (bool)result;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string property)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
        }
    }
}

Both code snippets will help you to reproduce my problem. The thing is that neither FilesFilePath command parameter can pass its value to Load Command, nor any of those changes in the DataContext can be viewed in MainWindow UI. Even though the Browse button gives value to parameter FilesFilePath, the UI cannot show this text. Recall that property .Text of FileNameTextBox is bound to FilesFilePath. So I want the UI to show that text also.

Summarizing I have two goals to achieve based on the snippet provided

  • Pass the value of FilesFilePath(string) between the two ICommands.
  • View the value of FilesFilePath(string) in UI after using the Browse ICommand.

I am more than willing to provide in the comments any additional info if something was unclear to you.

1

There are 1 best solutions below

5
Keithernet On

The reason why your code doesn't work is that you're never setting the FilesFilePath property.

In your BrowseFile method, you should set FilesFilePath if the result is true:

        //Browse function used in Browse ICommand
        public bool BrowseFile(string filepathselected)
        {
            ...

            // Get the selected file name and display in a TextBox.
            // Load content of file in a TextBlock
            if (result == true)
            {
                filepathselected = openFileDlg.FileName;

                // Set the FilesFilePath property here!
                FilesFilePath = filepathselected;

                Debug.WriteLine("2. File Path: " + filepathselected);
            }
            return (bool)result;
        }