c# - 绑定(bind) Button.IsEnabled() 属性无法正常工作

标签 c# silverlight xaml button binding

我是 MVVM 模式的新手。

我想知道为什么每次触发我的 TextChanged() 事件时,绑定(bind)的 IsEnabled() 属性都不会更改其状态。 TextChanged() 事件正在调用 IsValid() 来检查数据有效性。

我有这个简单的 ViewModel

public class myViewModel : ViewModel
{
    public bool IsOk { get; set; }
    public RelayCommand OnValidateExecute { get; set; }

    public myViewModel()
    {
        OnValidateExecute = new RelayCommand(p => IsValid(), p => true);
    }

    public bool IsValid()
    {
        // other codes
        IsOk = MethodName();
        NotifyPropertyChanged("IsOk");
    }
}

我在 IsValid() 上设置了一个断点,代码运行正常。我想知道为什么 IsEnabled 属性没有按预期工作。

这是我的XAML代码

<TextBox ...other propeties here....>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="TextChanged">
            <i:InvokeCommandAction Command="{Binding OnValidateExecute}">
            </i:InvokeCommandAction>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</TextBox>

<Button x:Name="btnSave" IsEnabled="{Binding IsOk, Mode=TwoWay}" 
            ...other propeties here....>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <i:InvokeCommandAction Command="{Binding OnSaveExecute}">
            </i:InvokeCommandAction>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

我想要的是,当 IsOk 属性为 false 时,按钮应该是 Disabled,否则,Enabled

我的数据绑定(bind)有问题吗?如果以前有人问过这个问题,请帮助我重定向到它。

更新 1

我在这段代码中遇到的另一个问题是,IsValid() 函数在文本框上设置值之前首先被触发。这是一个示例,假设文本框的起始值为 0,当我将其更改为 9 时,将要检查的值是先前的值 0 > 而不是 9。知道为什么会这样吗?绑定(bind)有问题吗?

最佳答案

这是答案,包括我的 MVVM 框架的重要部分。除此之外,我在上面添加了一些额外的功能。我不能把我所有的图书馆都放在这里。但我相信它会有所帮助。

如果您使用命令,您应该知道 ICommand 接口(interface)中的 CanExecuteChanged。您应该在属性更改时触发此命令。 (我不使用 RelayCommand,它是 3.party 。)

使用我的 DCommand :) 这是最重要的部分

它很容易实现, 并具有 FirePropertyChanged 方法。如果 ICommand 不为空,此方法将触发 CanExecuteChanged

一个示例命令

匿名语法

   DCommand commandPost=new DCommand(()=>{
      //TODO:Command's real execute method Post()
        },
      ()=>
      {
         return this.TextBoxBoundProperty.IsValid;
      }
    )

非匿名语法

    DCommand commandPost=(Post,Validate);

除此之外,您应该通过 viewModel 构造函数中的以下方法触发 canexecutechanged。

    this.PropertyChanged += (sender, prop) =>
          {
        //I preffered canExcuteChange for any property changes for my viewmodel class. You could put your own logic. if(prop.PropertyName.equals("thisone"));
        //Just works for this class's property changed
                this.InvokeOnClassPropertyChange(prop.PropertyName, () =>
                {
                    this.commandPost.FirePropertyChanged();
                });
          }

如果属性是 ViewModel 类的属性,InvokeOnClassPropertyChange 起作用。

    public static void InvokeOnClassPropertyChange(this object instance,string PropertyName,Action action)
    {
        Type type = instance.GetType();
        var fulllist = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(w => w.DeclaringType == type).ToList();
        if (fulllist.Select(p => p.Name).Contains(PropertyName))
        {
            action.Invoke();
        }
    }

上面的代码显示了 InvokeOnClassPropertyChange 扩展方法。 下面显示了我的 DCommand 实现 ICommand。

   public class DCommand :ICommand
    {
    public void FirePropertyChanged()
    {
        if (CanExecuteChanged!=null)
        CanExecuteChanged(this, EventArgs.Empty);            
    }

    Func<bool> CanExecuteFunc { get; set; }
    Action<object> Action { get; set; }


    public DCommand(Action<object> executeMethod)
    {
        this.Action = executeMethod;            
    }

    public DCommand(Action executeMethod)
    {
        this.Action = new Action<object>(
            (prm) =>
            {
                executeMethod.Invoke();
            }
            );
    }

    public DCommand(Action<object> executeMethod, Func<bool> canExecuteMethod)
        : this(executeMethod)
    {            
        this.CanExecuteFunc = canExecuteMethod;            
    }

    public DCommand(Action executeMethod, Func<bool> canExecuteMethod)
        : this(executeMethod)
    {
        this.CanExecuteFunc = canExecuteMethod;
    }

    public bool CanExecute(object parameter=null)
    {
        if (CanExecuteFunc == null)
            return true;

        return CanExecuteFunc.Invoke();
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter=null)
    {

        if (CanExecuteFunc == null || CanExecute(parameter))
        {
            Action.Invoke(parameter);                
        }

    }
}

毕竟, 如果您想在文本框的文本立即更改时更改您的 ViewModel 属性,您应该通过这种方式进行绑定(bind)。

Text="{Binding BoundProperty,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"

关于c# - 绑定(bind) Button.IsEnabled() 属性无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16805163/

相关文章:

c# - DispatcherTimer 的绑定(bind)不在 View 上显示它的值

entity-framework - EF/Silverlight 应用程序的项目结构

xaml - 有没有办法在 xaml 中包含 namespace ,这样我就不必编写扩展名了?

c# - 手动加载依赖程序集

asp.net - Silverlight 4 和 ASP.NET 的 WCF 故障异常

c# - 直接使用 Windows Azure Active Directory 进行身份验证,无需打开 Web 浏览器

c# - 骰子游戏的随机数

c# - Silverlight 和一个表单应用程序

c# - MVC 无法将 lambda 表达式转换为类型,因为它不是委托(delegate)

c# - 读取解决方案数据文件 ASP.Net Core