uwp当CanExecute为false时启用了主键的MVVM ContentDialog

uwp当CanExecute为false时启用了主键的MVVM ContentDialog

问题描述:

我尝试使用mvvm构建类似于https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.contentdialog中示例的ContentDialog。uwp当CanExecute为false时启用了主键的MVVM ContentDialog

对于CanExecute验证我已经创建了https://social.msdn.microsoft.com/Forums/en-US/6d5d6fd9-5f03-4cb6-b6c0-19ca01ddaab8/uwpcontentdialog-buttons-do-not-respect-canexecute?forum=wpdevelop

此作品描述的派生类ContentDialog但我怎样才能使按钮,它是可以点击的CanExecute验证。

这是我的解决方案。我创建了一个contentdialog扩展。所述扩展包含

  • 一个CancelableCommand命令
  • 一个CancelableCommandParameter参数
  • 和可绑定DialogCancel属性。

这些是我的扩展的附加属性。

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); 
     } 
    } 
    } 
} 

的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> 

这是视图模型

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 
    } 
    } 
} 

绑定到Views时,ICommand接口的CanExecuteChanged事件中缺少链接。它只有在完美的情况下才有效,而且凭借我的经验,它绝大多数都不是完美的。

诀窍是随时调用CanExecuteChanged,将CanExecute切换为true或false。

如果您使用的是中继命令,我所做的是在继电器命令中添加一个公共方法。

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

然后在属性或属性或值更改是否应该返回true或false只是调用该方法。

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

这可能会让你知道我在说什么。如果不是,或者您需要更多帮助,我可以发布更多的代码来解答这个问题。