在WPF表单上,我有一个超链接,单击该超链接时应该在重定向到内部网页之前聚合数据库中的一些数据。
目前,XAML 如下所示:
<Hyperlink RequestNavigate="Hyperlink_RequestNavigate" IsEnabled="{Binding CanTakePayment}">
Launch Payments Portal
</Hyperlink>
要做数据库的事情,Hyperlink_RequestNavigate
使用方法,驻留在View.xaml.cs
它看起来像:
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
var transactionReference = GetToken(100M, "13215", "product");
var url = string.Format("{0}New?transactionReference={1}", Settings.Default.PaymentUrlWebsite, transactionReference);
e.Handled = true;
}
我不喜欢这种机制在这里,更愿意将其移动到视图模型。
我尝试做的是添加到视图模型属性
public ICommand NavigateToTakePayment
{
get { return _navigateToTakePayment; }
set { _navigateToTakePayment = value; }
}
并在 XAML 中将绑定更改为
<Hyperlink RequestNavigate="{Binding Path=NavigateToTakePayment}" IsEnabled="{Binding CanTakePayment}">
Launch Payments Portal
</Hyperlink>
但它开始给我演员例外。
将此机制从视图移动到视图模型的最合适方法是什么?
HyperLink
是一个有点问题的孩子。它不支持命令绑定。
可以使用附加属性将命令绑定的支持硬塞进其中,但只需修改按钮即可执行相同的操作会更容易。
<Style TargetType="Button" x:Key="HyperlinkStyledButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<TextBlock Foreground="DodgerBlue"
Text="{TemplateBinding Content}"
TextDecorations="Underline"
Cursor="Hand" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
然后像这样使用超链接:
<Button Command="{Binding OpenHttpLinkCommand}" Content="www.google.com"
Style="{StaticResource HyperlinkStyledButton}" ToolTip="Some custom tooltip"/>
假设标准 MVVM 绑定正常工作:
在视图中模型:
public ICommand OpenHttpLinkCommand { get; }
在视图模型构造函数中:
this.OpenHttpLinkCommand = new DelegateCommand(this.OnOpenHttpLinkCommand);
以及带有链接打开浏览器的命令:
private void OnOpenHttpLinkCommand()
{
try
{
System.Diagnostics.Process.Start("http://www.google.com/");
}
catch (Exception)
{
// TODO: Error.
}
}
应用的问题在于ICommand
在使用前未初始化。
我有一个这样的命令实现:
public class RelayCommand : ICommand
{
Predicate<object> _canExecute;
Action<object> _execute;
bool _defaultBehaviourForCanExecute;
public RelayCommand(Action<object> execute, bool defaultBehaviourForCanExecute = true, Predicate<object> canExecute = null)
{
_canExecute = canExecute;
_execute = execute;
_defaultBehaviourForCanExecute = defaultBehaviourForCanExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute != null)
{
Logger.LogInformation("Evaluating can execute method for " + _canExecute.Method.DeclaringType + "->"+_canExecute.Method.Name);
return _canExecute.Invoke(parameter);
}
return _defaultBehaviourForCanExecute;
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, new EventArgs());
}
public void Execute(object parameter)
{
Logger.LogInformation("Executing command method for " + _execute.Method.DeclaringType + "->" + _execute.Method.Name);
_execute.Invoke(parameter);
RaiseCanExecuteChanged();
}
}
现在它正在我的ViewModel
中初始化,如下所示:
NavigateToTakePayment = new RelayCommand(navigateToTakePayment CommandMethod);//it also can take canExecute method if you need a condition before executing.
然后在您的 XAML 中,您可以像这样使用它:
<Hyperlink RequestNavigate="{Binding Path=NavigateToTakePayment}" IsEnabled="{Binding CanTakePayment}">
Launch Payments Portal
</Hyperlink>
顺便说一句:当您需要禁用超链接时,实现canexecute
方法
然后它将自动完成。如果您需要更多信息,我将更新我的答案。
快乐编码
旧线程,但对于那些像我一样仍然遇到它的人来说,Hyperlink
确实支持 ICommandBinding
,但你需要一个派生类来这样做:
using System.Windows.Documents;
public class HyperlinkCommander : Hyperlink
{
protected override void OnClick()
{
Command.Execute(null);
}
}
然后在 xaml 中使用它,就像在 ViewModel 中将Button
绑定到 ICommand 一样,在本例中称为 HyperlinkClickerCommand。 像这样:
<localControls:HyperlinkCommander Command="{Binding HyperlinkClickerCommand}" >
Click me!
</localControls:HyperlinkCommander>
在 xaml 顶部附近有这样的东西:
<Window
...
xmlns:localControls="clr-namespace:TestProject.Controls"
...
>
其中HyperlinkClickerCommand
是您在视图模型中要绑定到的命令。 如上所述的超链接将触发绑定命令的执行,并遵守它的 CanExecute。