c# - 在 Button1Command 中设置 Command.Parameter1 并在 Button2Command 中使用 Command.Parameter1 的值返回 null
问题描述
我有两个按钮命令。让我们称它们为BrowseButton1
and 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 也无法显示此文本。回想一下, 的属性.Text
是FileNameTextBox
绑定的FilesFilePath
。所以我希望用户界面也显示该文本。
总结一下,根据提供的代码段,我有两个目标要实现
FilesFilePath
在两个 ICommand 之间传递 (string) 的值。FilesFilePath
使用 Browse ICommand 后在 UI 中查看 (string) 的值。
如果您不清楚,我非常愿意在评论中提供任何其他信息。
解决方案
您的代码不起作用的原因是您从未设置该FilesFilePath
属性。
在您的BrowseFile
方法中,您应该设置FilesFilePath
ifresult
是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;
}
推荐阅读
- php - 未找到 InvalidArgumentException 视图 [auth.login]
- azure - 如何为指向 Azure AD 中单个 Web 应用程序的不同用户集设置两个不同的 SAML 应用程序
- oracle - 如何编写一个可以接受任意数据类型的可变数量参数的plsql存储过程?
- javascript - JavaScript 功能仅在页面重新加载后有效
- html - 如何在 html 表格列中打印一天中的小时数?
- flutter - Flutter:将 Base64 String 图像 url 转换为 File 并在 FileImage 或相关小部件中使用
- python - Flutter 和 python [AES] 之间的相同加密
- javascript - MuleSoft 解析模板参考
- c++ - SDL2 不会为重音键生成 KEYDOWN 和 KEYUP 事件
- django - django jsonField 过滤以从指定键中获取值列表