WPF MVVM将超链接RequestNavigate绑定到View模型

Mat*_*ius 5 c# wpf xaml hyperlink mvvm

在WPF表单上,我有一个超链接,当单击该超链接时,应该在重定向到内部网页之前在数据库中聚合一些数据。

当前XAML看起来如下:

<Hyperlink RequestNavigate="Hyperlink_RequestNavigate" IsEnabled="{Binding CanTakePayment}">
  Launch Payments Portal
</Hyperlink>
Run Code Online (Sandbox Code Playgroud)

做数据库使用的东西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;
}
Run Code Online (Sandbox Code Playgroud)

我不喜欢这种机制,而是希望将其移至View模型。

我试图做的是添加到ViewModel属性

public ICommand NavigateToTakePayment       
{
    get { return _navigateToTakePayment; }
    set { _navigateToTakePayment = value; }
}
Run Code Online (Sandbox Code Playgroud)

并在XAML中更改绑定到

<Hyperlink RequestNavigate="{Binding Path=NavigateToTakePayment}" IsEnabled="{Binding CanTakePayment}"> 
   Launch Payments Portal
</Hyperlink>
Run Code Online (Sandbox Code Playgroud)

但这开始给了我演员例外。

将这种机制从View移到ViewModel的最合适方法是什么?

Con*_*ngo 8

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>
Run Code Online (Sandbox Code Playgroud)

然后像这样使用超链接:

<Button Command="{Binding OpenHttpLinkCommand}" Content="www.google.com" 
        Style="{StaticResource HyperlinkStyledButton}" ToolTip="Some custom tooltip"/>
Run Code Online (Sandbox Code Playgroud)

假设标准 MVVM 绑定正常工作:

在视图模型中:

public ICommand OpenHttpLinkCommand { get; }
Run Code Online (Sandbox Code Playgroud)

在 ViewModel 构造函数中:

this.OpenHttpLinkCommand = new DelegateCommand(this.OnOpenHttpLinkCommand);
Run Code Online (Sandbox Code Playgroud)

以及使用链接打开浏览器的命令:

private void OnOpenHttpLinkCommand()
{
    try
    {
        System.Diagnostics.Process.Start("http://www.google.com/");
    }
    catch (Exception)
    {
        // TODO: Error.
    }
}
Run Code Online (Sandbox Code Playgroud)


XAM*_*MAX 5

您的应用存在的问题是,ICommand在使用前未初始化。
我有一个这样的Command实现:

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();
        }
    }  
Run Code Online (Sandbox Code Playgroud)

现在这ViewModel就像我这样初始化:

NavigateToTakePayment = new RelayCommand(navigateToTakePayment CommandMethod);//it also can take canExecute method if you need a condition before executing.  
Run Code Online (Sandbox Code Playgroud)

然后在您的xaml中像这样使用它:

<Hyperlink RequestNavigate="{Binding Path=NavigateToTakePayment}" IsEnabled="{Binding CanTakePayment}">
    Launch Payments Portal
</Hyperlink>
Run Code Online (Sandbox Code Playgroud)

顺便说一句:当您需要禁用超链接时,请执行一种canexecute方法
,然后将其自动完成。如果您需要更多信息,我将更新我的答案。
快乐编码