wpf 为什么我的按钮在使用Fody.PropertyChanged将文本添加到文本框时不启用?

ctzwtxfj  于 2023-04-13  发布在  其他
关注(0)|答案(2)|浏览(171)

我正在使用Fody.PropertyChanged来尝试减少我的WPF项目中的一些样板代码。
当我试图创建一个按钮单击事件时,Fody似乎不会像处理标签和字符串属性之间的绑定那样处理这个事件。
我有一个文本框,我希望根据此文本框是否有文本来启用/禁用一个按钮。我的XAML看起来像:

<Window x:Class="MyProject.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyProject"
        mc:Ignorable="d">
   <Label Content="Enter text:" HorizontalAlignment="Left" Margin="21,43,0,0" VerticalAlignment="Top"/>

   <TextBox Height="100" 
      TextWrapping="Wrap" 
      Text="{Binding Test}" 
      VerticalAlignment="Top" 
      Padding="5, 3, 1, 1"
      AcceptsReturn="True" Margin="161,10,10,0"/>

   <Button Content="Go" 
      IsEnabled="{Binding Path=GoButtonIsEnabled}"
      Command="{Binding Path=ButtonClick}"
      HorizontalAlignment="Left" 
      Margin="64,158,0,0" 
      VerticalAlignment="Top" Width="75"/>
</Window>

它绑定到的ViewModel为:

class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public ButtonCommandBinding ButtonClick { get; set; }
    public bool GoButtonIsEnabled => !String.IsNullOrWhiteSpace(Test);

    public string Test { get; set; }

    public MainWindowViewModel()
    {
        ButtonClick = new ButtonCommandBinding(OnGoButtonClick);
    }

    private void OnGoButtonClick()
    {
        System.Windows.MessageBox.Show("Hello, world!");
    }

    protected void NotifyPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

ButtonCommandBinding:

public class ButtonCommandBinding : ICommand
{
    private readonly Action handler;
    private bool isEnabled;

    public ButtonCommandBinding(Action handler)
    {
        this.handler = handler;
    }

    public bool IsEnabled
    {
        get { return isEnabled; }
        set
        {
            if (value != isEnabled)
            {
                isEnabled = value;
                CanExecuteChanged?.Invoke(this, EventArgs.Empty);
            }
        }
    }

    public bool CanExecute(object parameter)
    {
        return IsEnabled;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        if (IsEnabled)
        {
            handler();
        }
    }
}

我相信在文本框中输入不能启用按钮的原因是因为属性更改通知程序没有被调用..但我没有调用它,因为我使用的是Fody.我没有在我的ViewModel中实现NotifyPropertyChanged,直到我尝试按钮单击工作;在实现按钮click之前,这是由Fody处理的(当我只是将标签绑定到文本时)。
所以我有两个问题:
1.我是不是误解了,或者严重滥用了福迪的目的?
1.当Test属性不再为null或空白时,为什么按钮不启用?
编辑:感谢ANu告诉我添加[AlsoNotifyFor(nameof(GoButtonIsEnabled))]属性。然而,我现在遇到的问题是,当我加载ViewModel中设置的文本框时:

public MainWindowViewModel()
{
    Test = "Enter text here";
    ButtonClick = new ButtonCommandBinding(OnButtonClick);
    ButtonClick.IsEnabled = true;
}

...我运行应用程序,然后从文本框中删除文本,Go按钮不会禁用,直到我单击它。在我单击它之后,操作不会运行(因为它不应该运行,因为文本框是空的),按钮被禁用。当我在文本框中输入文本时,它不会重新启用。
似乎装订还是不能正常工作。

public bool GoButtonIsEnabled => !String.IsNullOrWhiteSpace(Test);

[AlsoNotifyFor(nameof(GoButtonIsEnabled))]
public string Test { get; set; }

public MainWindowViewModel()
{
    Test = "Enter text";
    ButtonClick = new ButtonCommandBinding(OnButtonClick);
    ButtonClick.IsEnabled = true;
}

XAML:

<Button Content="Go" 
   IsEnabled="{Binding Path=GoButtonIsEnabled}"
   Command="{Binding Path=ButtonClick}"
   HorizontalAlignment="Left" 
   Margin="64,158,0,0" 
   VerticalAlignment="Top" Width="75"/>
inkz8wg9

inkz8wg91#

Fody会根据您的需要为每个属性注入通知代码。但是,您还希望在另一个属性(Text)更改时通知依赖的属性(GoButtonIsEnabled)。
您需要使用AlsoNotifyFor属性来允许注入指向不同属性的通知代码。

[AlsoNotifyFor(nameof(GoButtonIsEnabled ))]
public string Test { get; set; }
ni65a41a

ni65a41a2#

Fody/PropertyChanged不支持嵌套引用的通知,请使用PostSharp

[AddINotifyPropertyChangedInterface]
public class Person
{
    public bool IsNameNotEmpty => !String.IsNullOrWhiteSpace(Name);
    public string? Name { get; set; }
}
[AddINotifyPropertyChangedInterface]
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    public bool IsNameNotEmpty => SomePerson.IsNameNotEmpty;
    public Person? SomePerson { get; set; } = new();
}
IsEnabled="{Binding IsNameNotEmpty}"  // Can not notify!
IsEnabled="{Binding SomePerson.IsNameNotEmpty}" // Can notify!

相关问题