选择组合框中的值时如何触发按钮命令
How to trigger button command whenever my value from combobox is selected
我有一个组合框和一个按钮。我希望每当我从中选择一项时,按钮都不会被禁用
XAML :
<Border Style="{StaticResource borderMain}"
Grid.Row="7"
Grid.Column="0">
<ComboBox ItemsSource="{Binding Source={StaticResource portNames}}"
SelectedItem="{Binding SelectedPort, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
x:Name="Port_Selector" Grid.Column="0"
Text="Port Selector" Background="White"/>
</Border>
<Border Style="{StaticResource borderMain}"
Grid.Column="1"
Grid.Row="7">
<Button Content="Connect"
Command="{Binding OpenPortCommand}"
CommandParameter="{Binding SelectedPort}"
Style="{StaticResource buttonMain}"
Margin="5"/>
</Border>
命令:
public class OpenPortCommand : ICommand
{
public OpenPortVM OpenPortVM{ get; set; }
public OpenPortCommand(OpenPortVM OpenPortVM)
{
this.OpenPortVM = OpenPortVM;
}
public event EventHandler? CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object? parameter)
{
string? portCom = parameter as string;
if (!string.IsNullOrEmpty(portCom))
return true;
return false;
}
public void Execute(object? parameter)
{
OpenPortVM.ConnectPort();
}
}
我已经调试了它并检查了我用于绑定的变量的值 SelectedPort
并且它有一个值但是不知何故,我的按钮的 CommandParameter 未检测到所以 CanExecute
方法是不 运行 正确。我错过了什么吗?
更新
预计:
结果:
更新 2
Setter 上的断点:
CanExecute
上的断点
您的 OpenPortCommand
缺少实际引发 CanExecuteChanged
事件的可能性。我建议如下:
public class OpenPortCommand : ICommand
{
public OpenPortVM OpenPortVM{ get; set; }
public OpenPortCommand(OpenPortVM OpenPortVM)
{
this.OpenPortVM = OpenPortVM;
}
// Leave this event as is, don't do an explicit implementation
public event EventHandler? CanExecuteChanged;
public void RaiseCanExecuteChange() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
public bool CanExecute(object? parameter) => !string.IsNullOrEmpty(parameter as string);
// rest ommitted
}
在您的 ViewModel 中 SelectedPort
属性:
public string SelectedPort
{
get => _selectedPort;
set
{
_selectedPort = value;
// call your OnPropertyChanged( ... );
OpenPortCommand?.RaiseCanExecuteChanged();
}
}
在 XAML 中,我简化了 ComboBox.SelectedItem
属性 的绑定,如下所示:
<ComboBox ... SelectedItem="{Binding SelectedPort}"/>
您的代码有两个问题:
- 最关键的是引发
INotifyPropertyChanged.PropertyChanged
事件的方式,它实际上会阻止您的代码正确执行。您当前没有传递 属性 名称,而是传递支持字段的名称。
而不是
OnPropertyChanged(nameof(portSelected));
一定是
OnPropertyChanged(nameof(SelectedPort));
为了简化事件调用,您的调用者应该使用 CallerMemberName
属性:
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
=> this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName);
然后调用不带任何参数的方法OnPropertyChanged
,因为属性名称现在会被自动检测到:
OnPropertyChanged();
- 方法
RaiseExecuteChangedCommand
是多余的。 ICommand
事件的 CanExecuteChanged
实现将事件处理程序委托给 CommandManager.RequerySuggested
事件(这是正确的)。 CommandManager.RequerySuggested
事件由 WPF 框架自动引发,并且由于事件委托,框架还将引发 ICommand.CanExecuteChanged
(因为您将所有 ICommand.CanExecuteChanged
处理程序附加到 CommandManager.RequerySuggested
事件,使用CommandManager.RequerySuggested += value
)。如果您不希望框架为您引发 CanExecuteChanged 事件,您必须删除 CommandManager.RequerySuggested += value
部分,即不要将客户端处理程序附加到 CommandManager.RequerySuggested
事件。因为现在您将从 RaiseExecuteChangedCommand
方法中明确提出它。所以你不能两者兼得。明确地提高 ICommand.CanExecuteChanged
或让 CommandManager
为你做。
我有一个组合框和一个按钮。我希望每当我从中选择一项时,按钮都不会被禁用
XAML :
<Border Style="{StaticResource borderMain}"
Grid.Row="7"
Grid.Column="0">
<ComboBox ItemsSource="{Binding Source={StaticResource portNames}}"
SelectedItem="{Binding SelectedPort, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
x:Name="Port_Selector" Grid.Column="0"
Text="Port Selector" Background="White"/>
</Border>
<Border Style="{StaticResource borderMain}"
Grid.Column="1"
Grid.Row="7">
<Button Content="Connect"
Command="{Binding OpenPortCommand}"
CommandParameter="{Binding SelectedPort}"
Style="{StaticResource buttonMain}"
Margin="5"/>
</Border>
命令:
public class OpenPortCommand : ICommand
{
public OpenPortVM OpenPortVM{ get; set; }
public OpenPortCommand(OpenPortVM OpenPortVM)
{
this.OpenPortVM = OpenPortVM;
}
public event EventHandler? CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object? parameter)
{
string? portCom = parameter as string;
if (!string.IsNullOrEmpty(portCom))
return true;
return false;
}
public void Execute(object? parameter)
{
OpenPortVM.ConnectPort();
}
}
我已经调试了它并检查了我用于绑定的变量的值 SelectedPort
并且它有一个值但是不知何故,我的按钮的 CommandParameter 未检测到所以 CanExecute
方法是不 运行 正确。我错过了什么吗?
更新
预计:
结果:
更新 2
Setter 上的断点:
CanExecute
上的断点
您的 OpenPortCommand
缺少实际引发 CanExecuteChanged
事件的可能性。我建议如下:
public class OpenPortCommand : ICommand
{
public OpenPortVM OpenPortVM{ get; set; }
public OpenPortCommand(OpenPortVM OpenPortVM)
{
this.OpenPortVM = OpenPortVM;
}
// Leave this event as is, don't do an explicit implementation
public event EventHandler? CanExecuteChanged;
public void RaiseCanExecuteChange() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
public bool CanExecute(object? parameter) => !string.IsNullOrEmpty(parameter as string);
// rest ommitted
}
在您的 ViewModel 中 SelectedPort
属性:
public string SelectedPort
{
get => _selectedPort;
set
{
_selectedPort = value;
// call your OnPropertyChanged( ... );
OpenPortCommand?.RaiseCanExecuteChanged();
}
}
在 XAML 中,我简化了 ComboBox.SelectedItem
属性 的绑定,如下所示:
<ComboBox ... SelectedItem="{Binding SelectedPort}"/>
您的代码有两个问题:
- 最关键的是引发
INotifyPropertyChanged.PropertyChanged
事件的方式,它实际上会阻止您的代码正确执行。您当前没有传递 属性 名称,而是传递支持字段的名称。
而不是
OnPropertyChanged(nameof(portSelected));
一定是
OnPropertyChanged(nameof(SelectedPort));
为了简化事件调用,您的调用者应该使用 CallerMemberName
属性:
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
=> this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName);
然后调用不带任何参数的方法OnPropertyChanged
,因为属性名称现在会被自动检测到:
OnPropertyChanged();
- 方法
RaiseExecuteChangedCommand
是多余的。ICommand
事件的CanExecuteChanged
实现将事件处理程序委托给CommandManager.RequerySuggested
事件(这是正确的)。CommandManager.RequerySuggested
事件由 WPF 框架自动引发,并且由于事件委托,框架还将引发ICommand.CanExecuteChanged
(因为您将所有ICommand.CanExecuteChanged
处理程序附加到CommandManager.RequerySuggested
事件,使用CommandManager.RequerySuggested += value
)。如果您不希望框架为您引发 CanExecuteChanged 事件,您必须删除CommandManager.RequerySuggested += value
部分,即不要将客户端处理程序附加到CommandManager.RequerySuggested
事件。因为现在您将从RaiseExecuteChangedCommand
方法中明确提出它。所以你不能两者兼得。明确地提高ICommand.CanExecuteChanged
或让CommandManager
为你做。