问题描述
我有两个按钮命令。我们称它们为browseButton1
和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"
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
方法中,如果FilesFilePath
为result
,则应设置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;
}