简体   繁体   English

当CanExecute为false时,带有启用主按钮的uwp MVVM ContentDialog

[英]uwp MVVM ContentDialog with enabled primary button when CanExecute is false

I try to build a ContentDialog similar to the example in https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.contentdialog with mvvm. 我尝试使用mvvm构建类似于https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.contentdialog中的示例的ContentDialog。

For the CanExecute validation I have created a derived ContentDialog class described in https://social.msdn.microsoft.com/Forums/en-US/6d5d6fd9-5f03-4cb6-b6c0-19ca01ddaab8/uwpcontentdialog-buttons-do-not-respect-canexecute?forum=wpdevelop 对于CanExecute验证,我创建了一个派生的ContentDialog类,在https://social.msdn.microsoft.com/Forums/en-US/6d5d6fd9-5f03-4cb6-b​​6c0-19ca01ddaab8/uwpcontentdialog-buttons-do-not-respect中描述-canexecute?论坛= wpdevelop

This works but how can I enable the button so it is clickable for the CanExecute validation. 这有效,但如何启用按钮,以便可以单击CanExecute验证。

There is a missing link in the CanExecuteChanged event of the ICommand interface when binding to Views. 绑定到视图时,ICommand接口的CanExecuteChanged事件中缺少链接。 It works only when it's a perfect situation and with my experience it's mostly never perfect for it. 只有当它是一个完美的情况时它才有效,而根据我的经验,它几乎从来都不是完美的。

The trick is to call CanExecuteChanged anytime the proper value changes that should switch the CanExecute to true or false. 诀窍是在适当的值更改时调用CanExecuteChanged,将CanExecute切换为true或false。

If you're using a relay command, what I've done is add a public method to the relay command. 如果您正在使用中继命令,我所做的是为relay命令添加一个公共方法。

public UpdateCanExecute() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);

Then in the property or properties or values that change whether or not this should return true or false just call that method. 然后在属性或属性或值中更改是否应返回true或false,只需调用该方法即可。

public bool IsWorking
{
    get { return isWorking; }
    set
    {
       isWorking = value;
       Notify(nameof(IsWorking));
       MyRelayCommand.UpdateCanExecute();
    }
}

This might give you an idea of what I'm talking about. 这可能会让你知道我在说什么。 If not or if you need more help I can post more code to this answer to help clarify. 如果没有,或者如果您需要更多帮助,我可以在此答案中发布更多代码以帮助澄清。

This is my solution. 这是我的解决方案。 I' ve created an contentdialog extension. 我创建了一个contentdialog扩展。 The extension contains 扩展名包含

  • a CancelableCommand command 一个CancelableCommand命令
  • a CancelableCommandParameter parameter CancelableCommandParameter参数
  • and the bindable DialogCancel property. 和可绑定的DialogCancel属性。

These are the attached properties of my extension. 这些是我的扩展程序的附加属性。

namespace BSE.UI.Xaml.Controls.Extensions
{
  public static class ContentDialog
  {
    public static readonly DependencyProperty DialogCancelProperty =
                DependencyProperty.RegisterAttached("DialogCancel",
                    typeof(bool),
                    typeof(ContentDialog), new PropertyMetadata(false));

    public static readonly DependencyProperty CancelableCommandParameterProperty =
                DependencyProperty.Register("CancelableCommandParameter",
                    typeof(object),
                    typeof(ContentDialog), null);

    public static readonly DependencyProperty CancelableCommandProperty =
                DependencyProperty.RegisterAttached("CancelableCommand",
                    typeof(ICommand),
                    typeof(ContentDialog),
                    new PropertyMetadata(null, OnCancelableCommandChanged));

    public static void SetDialogCancel(DependencyObject obj, bool value)
    {
      obj.SetValue(DialogCancelProperty, value);
    }

    public static bool GetDialogCancel(DependencyObject obj)
    {
      return (bool)obj.GetValue(DialogCancelProperty);
    }

    public static ICommand GetCancelableCommand(DependencyObject obj)
    {
      return (ICommand)obj.GetValue(CancelableCommandProperty);
    }

    public static void SetCancelableCommand(DependencyObject obj, ICommand value)
    {
      obj.SetValue(CancelableCommandProperty, value);
    }

    public static object GetCancelableCommandParameter(DependencyObject obj)
    {
      return obj.GetValue(CancelableCommandParameterProperty);
    }

    public static void SetCancelableCommandParameter(DependencyObject obj, object value)
    {
      obj.SetValue(CancelableCommandParameterProperty, value);
    }

    private static void OnCancelableCommandChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
      var contentDialog = obj as Windows.UI.Xaml.Controls.ContentDialog;
      if (contentDialog != null)
      {
        contentDialog.Loaded += (sender, routedEventArgs) =>
        {
         ((Windows.UI.Xaml.Controls.ContentDialog)sender).PrimaryButtonClick += OnPrimaryButtonClick;
        };
      }
    }

    private static void OnPrimaryButtonClick(Windows.UI.Xaml.Controls.ContentDialog sender, ContentDialogButtonClickEventArgs args)
    {
      var contentDialog = sender as Windows.UI.Xaml.Controls.ContentDialog;
      if (contentDialog != null)
      {
        var command = GetCancelableCommand(contentDialog);
        command?.Execute(GetCancelableCommandParameter(contentDialog));
        args.Cancel = GetDialogCancel(contentDialog);
      }
    }
  }
}

The xaml of the contentdialog looks like that contentdialog的xaml看起来像那样

<ContentDialog
    x:Class="MyClass.Views.MyContentDialog"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyClass.Views"
    xmlns:controlextensions="using:BSE.UI.Xaml.Controls.Extensions"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    PrimaryButtonText="Button1"
    SecondaryButtonText="Button2"
    controlextensions:ContentDialog.DialogCancel="{Binding Cancel}"
    controlextensions:ContentDialog.CancelableCommandParameter="{Binding}"
    controlextensions:ContentDialog.CancelableCommand="{Binding MyCancelableCommand}">

</ContentDialog>

This is the viewmodel 这是视图模型

namespace MyClass.ViewModels
{
  public class MyContentDialogViewModel : ViewModelBase
  {
    private ICommand m_myCancelableCommand;
    private bool m_cancel;

    public ICommand MyCancelableCommand=> m_myCancelableCommand ?? (m_myCancelableCommand = new RelayCommand<object>(CancelableSave));
    public bool Cancel
    {
      get
      {
        return m_cancel;
      }
      set
      {
        m_cancel = value;
        RaisePropertyChanged("Cancel");
      }
    }

    private void CancelableSave(object obj)
    {
      Cancel = !ValidateDialog();
    }

    private bool ValidateDialog()
    {
      return true// if saving successfull otherwise false
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM