【发布时间】:2021-02-20 21:46:14
【问题描述】:
我很难找到解决我的一个相当微不足道的问题的方法。
我有三个按钮执行相同的命令(相同的函数调用)。唯一改变的是函数调用会影响每个按钮的不同对象。因此,我没有创建 3 次按钮命令,而是创建了绑定到不同 MVVM 对象的命令参数。我下面的代码将清除一切。
我的问题是我不知道如何将命令参数绑定到 MVVM 对象。朝着这个方向我得到了以下错误
Object of type 'System.Windows.Data.Binding cannot be converted to 'System.Boolean' //or System.String
将元素绑定在一起的 XAML 代码(我还添加了 Peter 在提交的答案中提出的 MultiBinding.Converter 方法)
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"/>
<Binding Path="EnableFilesBrowseButton"/>
<Binding Path="EnableFilesLoadButton"/>
<Binding Path="EnableFilesViewButton"/>
<Binding Path="FilesPanelVisibility"/>
</MultiBinding>
</Button.CommandParameter>
</Button>
<Button
x:Name="LoadButton1"
Content="Load"
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>
<StackPanel
x:Name="StackPanelFiles"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Grid.Row="1"
Grid.Column="3"
Orientation="Vertical"
Width="400"
Height="36"
Margin="235,0,0,0"
Visibility="{Binding XPath=FilesPanelVisibility, Converter={StaticResource BooleanToVisibilityConverter}}">
</StackPanel>
<Button
x:Name="PreviewButton1"
IsEnabled="{Binding XPath=EnableFilesViewButton, Converter={StaticResource BooleanToVisibilityConverter}}"
Focusable="False"
Content="View"
Width="80"
Height="25"
Margin="545,0,0,0"
FontSize="10"
FontWeight="Light"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Grid.Column="3"
Grid.Row="1"
Cursor="Hand">
</Button>
<!--Apply ICommand to browse file 2nd time-->
<TextBox
Name="FileNameTextBoxLayout"
Text="{Binding Path=LayoutFilePath}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Height="25"
Margin="5,6,0,0"
IsReadOnly="True"
FontStyle="Italic"
FontFamily="Arial"
FontSize="9"
BorderThickness="0"
Grid.Column="2"
Grid.Row="3"/>
<Button
x:Name="BrowseButton2"
Content="Browse"
Command="{Binding Path=BrowseButtonCommand}"
IsEnabled="{Binding Path=EnableLayoutBrowseButton, 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="2"
Cursor="Hand">
<Button.CommandParameter>
<MultiBinding>
<MultiBinding.Converter>
<local:BrowseButtonConverter/>
</MultiBinding.Converter>
<Binding Path="LayoutFilePath"/>
<Binding Path="EnableLayoutBrowseButton"/>
<Binding Path="EnableLayoutLoadButton"/>
<Binding Path="EnableLayoutViewButton"/>
<Binding Path="LayoutPanelVisibility"/>
</MultiBinding>
</Button.CommandParameter>
</Button>
<Button
x:Name="LoadButton2"
Content="Load"
IsEnabled="{Binding Path=EnableLayoutLoadButton, 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="2"
Cursor="Hand">
</Button>
<!--...The rest of the controls as created above but with different names-->
</Grid>
</Window>
FilesFilePath、EnableFilesBrowseButton 等绑定元素是绑定到其他 XAML 对象并受 ICommand 影响的 MVVM 对象。
现在我向您展示带有 MVVM 对象和 ICommand 函数的 c# 代码: .cs 文件
namespace TestEnvironment
{
//Command parameters
public class BrowseButtonCommandParameters
{
public string FilePathSelected { get; set; } //parameter 1
public bool EnableBrowseButton { get; set; } //parameter 2
public bool EnableLoadButton { get; set; } //parameter 3
public bool EnableViewButton { get; set; } //parameter 4
public bool VisibilityPanel { get; set; } //parameter 5
}
//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],
EnableViewButton = (bool)values[3],
VisibilityPanel = (bool)values[4],
};
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException("to-source binding mode not supported");
}
}
public class MainWindowViewModel : INotifyPropertyChanged
{
//----------------------------------------------------------------------------------------------------
//MVVM objects binded 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 bool _enableFilesViewButton;
public bool EnableFilesViewButton
{
get
{
return _enableFilesViewButton;
}
set
{
_enableFilesViewButton = value;
OnPropertyChanged("EnableFilesViewButton");
}
}
//4.
private string _FilesFilePath;
public string FilesFilePath
{
get
{
return _FilesFilePath;
}
set
{
_FilesFilePath = value;
OnPropertyChanged("FilesFilePath");
}
}
//5.
private bool _changeFilesPanelVisibility;
public bool FilesPanelVisibility
{
get
{
return _changeFilesPanelVisibility;
}
set
{
_changeFilesPanelVisibility= value;
OnPropertyChanged("FilesPanelVisibility");
}
}
//Used by BrowseButton2
//1.
private bool _enableLayoutLoadButton;
public bool EnableLayoutLoadButton
{
get
{
return _enableLayoutLoadButton;
}
set
{
_enableLayoutLoadButton = value;
OnPropertyChanged("EnableLayoutLoadButton");
}
}
//2.
private bool _enableLayoutBrowseButton;
public bool EnableLayoutBrowseButton
{
get
{
return _enableLayoutBrowseButton;
}
set
{
_enableLayoutBrowseButton = value;
OnPropertyChanged("EnableLayoutBrowseButton");
}
}
//3.
private bool _enableLayoutViewButton;
public bool EnableLayoutViewButton
{
get
{
return _enableLayoutViewButton;
}
set
{
_enableLayoutViewButton = value;
OnPropertyChanged("EnableLayoutViewButton");
}
}
//4.
private string _LayoutFilePath;
public string LayoutFilePath
{
get
{
return _LayoutFilePath;
}
set
{
_LayoutFilePath = value;
OnPropertyChanged("LayoutFilePath");
}
}
//5.
private bool _changeLayoutPanelVisibility;
public bool LayoutPanelVisibility
{
get
{
return _changeLayoutPanelVisibility;
}
set
{
_changeLayoutPanelVisibility= value;
OnPropertyChanged("LayoutPanelVisibility");
}
}
//----------------------------------------------------------------------------------------------------
//ICommand: BrowseButtonCommand
public ICommand BrowseButtonCommand
{
get { return new DelegateCommand<object>(FuncBrowseCommand); }
}
public void FuncBrowseCommand(object parameters)
{
var param = (BrowseButtonCommandParameters)parameters;
//Load button gets instantly disabled when every time the user clicks the Browse Button
param.EnableLoadButton = false;
Nullable<bool> browse_result = BrowseFile(param.FilePathSelected);
//Browse file
if (browse_result == true)
{
param.EnableBrowseButton = true;
param.EnableLoadButton = true;
param.EnableViewButton = false;
param.VisibilityPanel = false;
}
else
{
return;
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string property)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
}
注意:在 ICommand 函数 BrowseButtonCommand 内部,我调用了一个名为 BrowseFile 的方法。不要太在意,因为我介绍的功能完美无缺。
我的目标和关注点是如何将命令参数与 MVVM 对象绑定并采用它们的值。如何将 command.parameter 值传递给 MVVM 对象。比如我想让命令参数FilePathSelected得到MVVM对象FilesFilePath的值
然后,当我对不同的浏览按钮 BrowseButton2 使用相同的命令时,我应该能够提供我的第二个浏览按钮的 MVVM 对象的值,例如
<Button
x:Name="BrowseButton2"
Content="Browse"
Command="{Binding Path=BrowseButtonCommand}">
<Button.CommandParameter> //Parameters that share value with MVVM objects of the second Browse Button
<local:BrowseButtonCommandParameters FilePathSelected="{Binding Path=LayoutFilePath}" //those return the error I mentioned earlier.
EnableBrowseButton="{Binding Path=EnableLayoutBrowseButton}"
EnableLoadButton="{Binding Path=EnableLayoutLoadButton}"
EnableViewButton="{Binding Path=EnableLayoutViewButton}"
VisibilityPanel="{Binding Path=LayoutPanelVisibility}"/>
</Button.CommandParameter>
</Button>
你知道我怎样才能做到这一点吗?我认为我走在正确的道路上,尽管很明显我错过了一些东西。我已经创建了我的 MVVM 对象,我的 ICommand 函数,尽管我想将它们绑定在一起,以便一个取另一个的值。正如我提到的,我需要为三个浏览按钮(BrowseButton1、BrowseButton2、BrowseButton3)执行此操作。因此,我不想创建三个 ICommand,而是只创建一个。
我非常愿意与您分享有关我的问题的更多信息,以防出现误解。
【问题讨论】: