在Button1Command中设置Command.Parameter1并使用Button2Command中Command.Parameter1的值返回null

问题描述

我有两个按钮命令。我们称它们为browseButton1LoadButton1。第一条命令浏览文件路径(MVVM对象)并将其设置为我的机器的本地路径。然后,第二个ICommand(也称为LoadButton1)使用该文件路径(相同的MVVM对象)将一些数据加载到sql表中。

我的问题是我不能在第二个ICommand中使用文件路径的值,因为它返回了 null

XAML代码

<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"
        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"
            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"
            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"
            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文件

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,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,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,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));
        }
    }
}

这两个代码段都将帮助您重现我的问题。问题是FilesFilePath命令参数都不能将其值传递给Load Command,也不能在MainWindow UI中查看DataContext中的任何更改。即使“浏览”按钮为参数FilesFilePath提供了值,UI也无法显示此文本。回想一下.Text属性FileNameTextBox已绑定到FilesFilePath。因此,我希望用户界面也显示该文本。

总结根据提供的摘要我有两个目标要实现

  • 在两个ICommand之间传递FilesFilePath(字符串)的值。
  • 使用浏览ICommand后,在UI中查看FilesFilePath(字符串)的值。

如果您不清楚某些内容,我很乐意在评论中提供任何其他信息。

解决方法

您的代码无法正常工作的原因是,您从未设置FilesFilePath属性。

BrowseFile方法中,如果FilesFilePathresult,则应设置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;
        }