C# 绑定按钮.IsEnabled()属性不存在';我不能正常工作

C# 绑定按钮.IsEnabled()属性不存在';我不能正常工作,c#,silverlight,xaml,button,binding,C#,Silverlight,Xaml,Button,Binding,我是MVVM模式的新手 我想知道为什么每次触发我的TextChanged()事件时,绑定的IsEnabled()属性都不会更改其状态。TextChanged()事件正在调用IsValid()检查数据验证 我有一个简单的ViewModel类 public class myViewModel : ViewModel { public bool IsOk { get; set; } public RelayCommand OnValidateExecute { get; set; }

我是MVVM模式的新手

我想知道为什么每次触发我的
TextChanged()
事件时,绑定的
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
code

<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时,按钮应该是
禁用的
,否则,
启用的

我的数据绑定有问题吗?如果以前有人问过这个问题,请帮我转到它

更新1

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

下面是我的代码:

<StackPanel>
    <TextBox x:Name="TextBox1" Margin="5,0,5,0" Width="100">
         <i:Interaction.Triggers>
               <i:EventTrigger EventName="TextChanged">
                    <i:InvokeCommandAction Command="{Binding OnValidateExecute, Mode=OneWay}" CommandParameter="{Binding Text,ElementName=TextBox1}" />
               </i:EventTrigger>
         </i:Interaction.Triggers>
    </TextBox>

    <Button x:Name="btnSave" Width="120" Height="25" Content="click" IsEnabled="{Binding IsOk}">
         <i:Interaction.Triggers>
               <i:EventTrigger EventName="Click">
                    <i:InvokeCommandAction Command="{Binding OnSaveExecute}">
                    </i:InvokeCommandAction>
               </i:EventTrigger>
         </i:Interaction.Triggers>
    </Button>
</StackPanel>
它工作得很好


希望这有帮助。

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

如果使用命令,应注意
ICommand
界面中的
CanExecuteChanged
。当属性更改时,应触发此命令。(我不使用RelayCommand,它是3.0版本的party。)

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

易于实施,, 并已更改
FireProperty
方法。如果ICommand的
CanExecuteChanged
,则此方法将激发该命令的

示例命令

匿名语法

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

    DCommand commandPost=(Post,Validate);
除此之外,还应在viewModel的ctor中通过以下方法触发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);                
        }

    }
}
公共类DCommand:ICommand
{
公共空间FirePropertyChanged()
{
如果(CanExecuteChanged!=null)
CanExecuteChanged(此为EventArgs.Empty);
}
Func CanExecuteFunc{get;set;}
动作动作{get;set;}
公共数据命令(操作执行方法)
{
this.Action=executeMethod;
}
公共数据命令(操作执行方法)
{
this.Action=新操作(
(prm)=>
{
executeMethod.Invoke();
}
);
}
公共数据命令(Action executeMethod、Func canExecuteMethod)
:此(执行方法)
{            
this.CanExecuteFunc=canExecuteMethod;
}
公共数据命令(Action executeMethod、Func canExecuteMethod)
:此(执行方法)
{
this.CanExecuteFunc=canExecuteMethod;
}
公共布尔CanExecute(对象参数=null)
{
如果(CanExecuteFunc==null)
返回true;
返回CanExecuteFunc.Invoke();
}
公共事件处理程序CanExecuteChanged;
public void Execute(对象参数=null)
{
如果(CanExecuteFunc==null | | CanExecute(参数))
{
Action.Invoke(参数);
}
}
}
毕竟,, 如果要在textbox的文本立即更改时更改ViewModel属性,则应通过这种方式进行绑定


Text=“{Binding BoundProperty,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}”

要完成Davut Gürbüz回答:

按钮上
您有一个,使用此属性优于
i:Interaction.Triggers
(易读)

像Davut Gürbüz说的,有一个。如果使用此属性,按钮的状态将自动更改

Xaml代码:

<TextBox
    Text="{Binding BoundProperty,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
    ...other propeties here.... />
<Button
    x:Name="btnSave"
    Command="{Binding OnSaveExecute}"
    ...other propeties here.... />

C#

//
///获取OnSaveExecute。
/// 
公共中继命令存储执行
{
得到
{
返回_onSaveExecute
?(\u onSaveExecute=新继电器命令(
() =>
{
//保存操作或调用保存方法
},
()=>IsOk);
}
}
私人中继通信;
/// 
///设置并获取IsOk属性。
///更改该属性的值将引发PropertyChanged事件。
/// 
公共图书馆
{
获取{return\u isOk;}
设置
{
如果(_isOk==值)
{
返回;
}
_isOk=值;
RaisePropertyChanged(“IsOk”);
OnSaveExecute.RaiseCanExecuteChanged();
}
}
private bool_isOk=假;
/// 
///设置并获取BoundProerty属性。
///更改该属性的值将引发PropertyChanged事件。
/// 
公共字符串边界属性
{
获取{return\u boundProerty;}
设置
{
if(_boundProerty==值)
{
返回;
}
_boundProerty=值;
RaisePropertyChanged(“BoundProerty”);
IsValid();
}
}
私有字符串_boundProerty=false;
公共myViewModel()
{
}
公共bool是有效的()
{
//其他代码
IsOk=MethodName();
}

“IsEnabled”属性未按预期工作-您对该属性的真正期望是什么?s
<TextBox
    Text="{Binding BoundProperty,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
    ...other propeties here.... />
<Button
    x:Name="btnSave"
    Command="{Binding OnSaveExecute}"
    ...other propeties here.... />
/// <summary>
/// Gets the OnSaveExecute.
/// </summary>
public RelayCommand OnSaveExecute
{
    get
    {
        return _onSaveExecute 
            ?? (_onSaveExecute = new RelayCommand(
                                    () =>
                                    {
                                              // Save action or call save method
                                    },
                                    () => IsOk));
    }
}
private RelayCommand _onSaveExecute;

/// <summary>
/// Sets and gets the IsOk property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public bool IsOk
{
    get { return _isOk; }
    set
    {
        if (_isOk == value)
        {
            return;
        }
        _isOk = value;
        RaisePropertyChanged("IsOk");
        OnSaveExecute.RaiseCanExecuteChanged();
    }
}
private bool _isOk = false;

/// <summary>
/// Sets and gets the BoundProerty property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public string BoundProerty
{
    get { return _boundProerty; }
    set
    {
        if (_boundProerty == value)
        {
            return;
        }
        _boundProerty = value;
        RaisePropertyChanged("BoundProerty");
        IsValid();
    }
}
private string _boundProerty = false;

public myViewModel()
{
}

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