首页 > 解决方案 > 在不禁用命令的情况下禁用按钮单击事件?

问题描述

我正在使用 MVVM 在 WPF 中创建应用程序,其中我显示一个带有保存文件名和路径文本框的页面。这些文本框经过大量实时验证(路径太短、太长、无效字符等),并且“保存”按钮只有在文件和路径都有效时才会变为活动状态。但是,我将留下一些最终检查,例如目录是否存在、文件是否已存在等,直到用户点击保存按钮。

问题是我有点作弊并使用按钮和按钮在clickViewModel中进行最后一分钟的保存或清理。在这种情况下,该命令将处理,但当它完成时,无论验证结果如何,单击都会立即触发。所以,不知何故,我需要启用或禁用 click 事件,直到我们知道最终的验证结果。Navigation Servicecommand

看法:

<TextBlock>
    Backup Name:
</TextBlock>

<TextBlock Text="{Binding Path=(Validation.Errors)/ErrorContent, 
                   ElementName=BackupFileNameTextBox}"/>

<TextBox x:Name="BackupFileNameTextBox"
         Text="{Binding BackupFileName, Mode=TwoWay, 
                UpdateSourceTrigger=PropertyChanged, 
                ValidatesOnNotifyDataErrors=True}"/>

... File Path Code same as above...

<Button Click="Pg9SaveBtnClick"
        Command="{Binding SaveBtnCommand}">
    Save
</Button>

代码背后

public Pg9BackupIntro()
{
   InitializeComponent();
}

private void Pg9SaveBtnClick(object sender, RoutedEventArgs e)
{
   // What I want to do
   if(binding.ViewModel.SaveClickEnabled) //<- Something like this
   {
       if (NavigationService.CanGoForward)
           NavigationService.GoForward();
       else
       {
           Pg10Backup page = new Pg10Backup();
           NavigationService.Navigate(page);
       }
   }
}

private void Pg9BackBtnClick(object sender, RoutedEventArgs e)
{
    NavigationService.GoBack();
}

视图模型:

public RelayCommand SaveBtnCommand { get; private set; }

public Pg9BackupIntroViewModel()
{
   SetupBackupSave();
   SaveBtnCommand = new RelayCommand(SetBackupFileData, CanSetBackupFileData);    
}

private string _backupFileName;
public string BackupFileName
{
    get { return _backupFileName; }
    set
    {
        _backupFileName = value;
        validateFileName();
        RaisePropertyChanged();
     }
}

... BackupFilePath prop same as above...

private bool _saveClickEnabled = false;
public bool SaveClickEnabled
{
    get { return _saveClickEnabled; }
    set
    {
        _saveClickEnabled = value;
        RaisePropertyChanged();
    }
}

private bool CanSetBackupFileData(object obj)
{
    if(HasErrors)
        return false;

    return true;
}

private void SetBackupFileData(object obj)
{
    finalValidation();

    if(!HasErrors)
       SaveClickEnabled = true;
    else 
       SaveClickEnabled = false;
}

我能想到的最简单的事情(如上所示)是在 VM 中创建一个名为“SaveClickEnable”的属性,并在绑定到该属性的代码中。然后我们可以简单地检查 click 事件处理程序中的属性并调用Navigation Serviceif 一切正常。不幸的是,我看过的所有教程都只涉及通过文本框等 UI 元素进行绑定,而不是绑定到变量背后的代码。这是我尝试的绑定方法:

public Pg9BackupIntro()
{
   InitializeComponent();
   Binding binding = new Binding();
   binding.Source = ViewModel or Datacontext;  //<- don't understand syntax here
   binding.Path = ViewModel.SaveClickEnabled;
}

另一个想法是可能使用 2 个按钮;1 代表command, 1 代表click。该click按钮将永远不可见,但会根据 VM 中设置的属性以某种方式触发单击。

这些都可能吗?我试过两者都做,但我的菜鸟妨碍了。我也尝试过绑定,IsHitTestVisible但这也会禁用command.

<Button IsHitTestVisible="{Binding SaveClickEnabled}" //<- Disables command too
        Click="Pg9SaveBtnClick"
        Command="{Binding SaveBtnCommand}">
    Save
</Button>

有没有一种简单的方法可以做到这一点?

标签: c#wpfmvvmdata-binding

解决方案


我通过创建一个隐藏的复选框并将其IsChecked属性绑定到SaveClickEnabled. 然后我只需检查 click 方法中复选框的值,如果出现错误,它会绕过导航代码。

看法:

<CheckBox x:Name="ClickEnabledCheckbox" 
                  Visibility="Collapsed" 
                  IsChecked="{Binding SaveClickEnabled}"/> 

代码隐藏:

private void Pg9BackupBtnClick(object sender, RoutedEventArgs e)
{
    if(ClickEnabledCheckbox.IsChecked == true)
    {
        ...Navigate to next View
    }
} 

视图模型:

private bool _saveClickEnabled = false;
public bool saveClickEnabled
{
    get { return _backupClickEnabled; }
    set
    {
        if (HasErrors)
            _backupClickEnabled = false;

         _backupClickEnabled = true;
         RaisePropertyChanged();
     }
}

它的美妙之处在于,我不想在用户可能正在输入有效文件路径或我们可以为他们创建的路径的整个过程中对他们咆哮。所以这只检查点击/命令上的那些类型的错误,当用户试图纠正他/她的错误时,错误就会消失,直到下一次按下。

我唯一的愿望是它更干净一些,似乎应该有办法消除复选框。


推荐阅读