wpf 为什么ViewModel在尝试通过Command从View传递Property时会得到null?

swvgeqrz  于 2023-08-07  发布在  其他
关注(0)|答案(2)|浏览(126)

因此,我尝试通过Command将MyProperty从View的代码隐藏传递到ViewModel。它看起来像这样:

视图:code-behind .xaml.cs

public partial class MainWindow : Window
{
    public string MyProperty { get; set; }
    
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Test_Click(object sender, RoutedEventArgs e)
    {
        MyProperty = "test click";
    }
}

字符串

视图:.xaml

<MenuItem Header="Test" CommandParameter="{Binding ElementName=MainWindow, Path=MyProperty}" Command="{Binding Test}"  Click="Test_Click"></MenuItem>

ViewModel:

private RelayCommand _test;

public RelayCommand Test { 
    get 
    {
        if (_test != null)
        {
            return _test;
        }

        return _test = new RelayCommand(obj =>
        {
            MessageBox.Show($"{obj}"); // here obj = null why? 
        });
    }
}

RelayCommand:

internal class RelayCommand : ICommand
{
    private Action<object> _execute;
    private Func<object, bool> _canExecute;

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}


我也试过使用RelativeSource代替ElementName,但不起作用:

<MenuItem Command="{Binding DataContext.Test, RelativeSource={RelativeSource AncestorType=views:MainWindow}}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=views:MainWindow}, Path=MyProp}" Click="Test_Click"></MenuItem>


我的问题是:
1.为什么它不工作?
1.哪种约束力?当我首先运行调试时,将Event_Click,然后CanExecute,然后Execute -这里MyProperty已经从Event_Click设置,但无论如何命令都为空。

yftpprvb

yftpprvb1#

只有在属性值发生更改时发出通知,绑定才对属性起作用。简单属性不执行任何通知。在View中,您可以声明一个DependencyProperty,它将为绑定执行通知

public partial class MainWindow : Window
{
    public string MyProperty
    {
        get { return (string)GetValue( MyPropertyProperty ); }
        set { SetValue( MyPropertyProperty, value ); }
    }

    // Using a DependencyProperty as the backing store for MyPropertyB.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MyPropertyProperty =
        DependencyProperty.Register( "MyProperty", typeof( string ), typeof( MainWindow ), new PropertyMetadata( null ) );

    private void Button_Click( object sender, RoutedEventArgs e )
    {
        MyProperty = "From Button_Click";
    }
}

个字符

ej83mcc0

ej83mcc02#

因此,对于第一种方法,当使用ElementName绑定时,您试图绑定到的元素必须具有使用x:Name="name"声明的名称。DisplayName不用于绑定。因此,请确保您使用的是元素的实际名称。
此外,名称不能与类型相同,因此MainWindow类型的窗口不能有x:Name="MainWindow"
对于第二次尝试,您缺少FindAncestor,相对绑定的正确语法是:

CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=views:MainWindow}, Path=MyProperty}"

字符串
稍后编辑:如果您没有看到属性的更新值,则它需要是DependencyProperty,或者您可以在设置其值时实现INotifyPropertyChanged并发出PropertyChanged

相关问题