首页 > 解决方案 > 在 Button1Command 中设置 Command.Parameter1 并在 Button2Command 中使用 Command.Parameter1 的值返回 null

问题描述

我有两个按钮命令。让我们称它们为BrowseButton1and LoadButton1。第一个命令浏览文件路径(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,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 文件

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

这两个代码片段都将帮助您重现我的问题。问题是两个FilesFilePath命令参数都不能将其值传递给加载命令,也不能在 MainWindow UI 中查看 DataContext 中的任何这些更改。即使 Browse 按钮​​为 parameter 赋值FilesFilePath,UI 也无法显示此文本。回想一下, 的属性.TextFileNameTextBox绑定的FilesFilePath。所以我希望用户界面也显示该文本。

总结一下,根据提供的代码段,我有两个目标要实现

如果您不清楚,我非常愿意在评论中提供任何其他信息。

标签: c#wpfimultivalueconverter

解决方案


您的代码不起作用的原因是您从未设置该FilesFilePath属性。

在您的BrowseFile方法中,您应该设置FilesFilePathifresulttrue

        //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;
        }

推荐阅读