【问题标题】:RelayCommand Params & BindingRelayCommand 参数和绑定
【发布时间】:2012-08-15 15:15:56
【问题描述】:

查看:

使用 WPF(MVVM) 玩一个基本的计算器。 我有 1 个文本框用于第一个数字,1 个文本框用于第二个数字,1 个文本块用于结果和 1 个按钮来执行 AddCommand 并返回结果。 将这些控件绑定到正确数据的正确 XAML 语法是什么。

型号:

public class Operation : INotifyPropertyChanged
{
    private double _result;
    public Operation()
    {
        _result = 0;
    }

    public double Result
    {
        get { return _result; }
        set
        {
            if (value != _result)
            {
                _result = value;
                RaisePropertyChanged("Result");
            }
        }
    }

    public double DoAdd(double first, double second)
    {
        _result = first + second;
        return _result;
    }
}

视图模型:

public class CalcViewModel
{
    private Operation _operation;
    public RelayCommand AddCommand { get; set; }

    public CalcViewModel()
    {
        _operation = new Operation();

        // This is not correct, how to define the AddCommand here so it takes two params
        // The first and second nums to work with.
        AddCommand = new RelayCommand(first, second => ExecuteAddCommand(first, second));
    }

    private void ExecuteAddCommand(double first, double second)
    {

        // How to bind this returned double to the TextBlock in View
        _oepration.DoAdd(first, second);
    }
}

应 Vlad 的要求编辑新版本的代码

型号:

public class Operation
    {
        private double _result;

        public Operation()
        {
            _result = 0;
        }

        public double Result
        {
            get { return _result; }
        }

        public void PerformAdd(double leftNum, double rightNum)
        {
            _result = leftNum + rightNum;
        }
    }

视图模型:

 public class CalcViewModel
    {
        private Operation _operation;
        public double LeftNumber { get; set; }
        public double RightNumber { get; set; }
        public double Result { get; set; }

        public RelayCommand AddCommand { get; set; }

        public CalcViewModel()
        {
            AddCommand = new RelayCommand(a => ExecuteAddCommand());
            _operation = new Operation();
        }

        private void ExecuteAddCommand()
        {
            _operation.PerformAdd(LeftNumber, RightNumber);
            Result = _operation.Result;
        }

查看 XAML:

<TextBox Text="{Binding LeftNumber}" />
<TextBox Text="{Binding RightNumber}" />
<TextBox Text="{Binding Result}" />
<Button Content="Add" Command="{Binding AddCommand}" />

查看后面的代码:

public partial class CalcUserControl : UserControl
{
    CalcViewModel vm;

    public CalcUserControl()
    {
        InitializeComponent();
        vm = new CalcViewModel();
        this.DataContext = vm;
    }
}

我尝试了所有绑定模式,但没有任何结果。我这里还有一个问题,这种情况下默认绑定模式是什么?

我什至认为它与计算的数据类型有关,所以我从 double 切换到 int,但仍然无法正常工作。

【问题讨论】:

    标签: wpf mvvm binding relaycommand


    【解决方案1】:

    好吧,让我们看看能做些什么。

    1) 型号。该模型不需要任何花哨的东西。我会保持简单,让它只返回值而不使用NotifyPropertyChanged。毕竟是模特。

    public class BinaryOperation
    {
        double _l, _r, _result = 0.0;
        public Operation(double l, double r)
        {
            _l = l; _r = r;
        }
    
        public double Result
        {
            get { return _result; }
        }
    
        public PerformAdd()
        {
            _result = _l + _r;
        }
    }
    

    2) 视图模型。在这里,您的 RelayCommand 并不需要任何参数。但是您需要将操作数的值存储在您的 VM 中,以便您的视图可以绑定到它们,而不是在命令中发送它们。请记住,业务逻辑不属于视图,视图只是盲目地绑定到虚拟机!因此,您的 VM 中需要 3 个 DP(左加数、右加数、结果)。

    3) 当命令到达时,您只需从 VM 中获取加数,要求模型执行操作,检索结果并将其分配给 VM 的结果 DP。 (目前,您的模型操作很快,因此您不需要以异步方式进行。但也许将来......)

    4) 查看。您需要将 Window/UserControl 绑定到 VM 的属性。 它会很简单:

    <TextBox Text="{Binding LeftAddend}"/>
    <TextBox Text="{Binding RightAddend}"/>
    <TextBox Text="{Binding Result}"/>
    <Button Command="{Binding AddCommand}">Add</Button>
    

    (别忘了把DataContext设置好。)

    编辑:
    VM 类必须是依赖对象!并且属性应该被定义为依赖属性。像这样的:

    public class CalcViewModel : DependencyObject
    {
        private Operation _operation;
    
        public double LeftNumber
        {
            get { return (double)GetValue(LeftNumberProperty); }
            set { SetValue(LeftNumberProperty, value); }
        }
    
        public static readonly DependencyProperty LeftNumberProperty = 
            DependencyProperty.Register("LeftNumber", typeof(double), typeof(CalcViewModel));
    
        public double RightNumber
        {
            get { return (double)GetValue(RightNumberProperty); }
            set { SetValue(RightNumberProperty, value); }
        }
    
        public static readonly DependencyProperty RightNumberProperty = 
            DependencyProperty.Register("RightNumber", typeof(double), typeof(CalcViewModel));
    
        public double Result
        {
            get { return (double)GetValue(ResultProperty); }
            set { SetValue(ResultProperty, value); }
        }
    
        public static readonly DependencyProperty ResultProperty = 
            DependencyProperty.Register("Result", typeof(double), typeof(CalcViewModel));
    
        public RelayCommand AddCommand { get; set; }
    
        public CalcViewModel()
        {
            AddCommand = new RelayCommand(a => ExecuteAddCommand());
            _operation = new Operation();
        }
    
        private void ExecuteAddCommand()
        {
            _operation.PerformAdd(LeftNumber, RightNumber);
            Result = _operation.Result;
        }
    }
    

    或者,如果您想使用 INotifyPropertyChanged 进行操作,并且您正在使用 .NET 4.5

    public class CalcViewModel : INotifyPropertyChanged
    {
        private Operation _operation;
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    
        double _leftNumber;
        public double LeftNumber
        {
            get { return _leftNumber; }
            set
            {
                if (value == _leftNumber) return;
                _leftNumber = value;
                NotifyPropertyChanged();
            }
        }
    
        double _rightNumber;
        public double RightNumber
        {
            get { return _rightNumber; }
            set
            {
                if (value == _rightNumber) return;
                _rightNumber = value;
                NotifyPropertyChanged();
            }
        }
    
        double _result;
        public double Result
        {
            get { return _result; }
            set
            {
                if (value == _result) return;
                _result = value;
                NotifyPropertyChanged();
            }
        }
    
        public RelayCommand AddCommand { get; set; }
    
        public CalcViewModel()
        {
            AddCommand = new RelayCommand(a => ExecuteAddCommand());
            _operation = new Operation();
        }
    
        private void ExecuteAddCommand()
        {
            _operation.PerformAdd(LeftNumber, RightNumber);
            Result = _operation.Result;
        }
    }
    

    与旧的 .NET 版本相同:

        void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    
        double _leftNumber;
        public double LeftNumber
        {
            get { return _leftNumber; }
            set
            {
                if (value == _leftNumber) return;
                _leftNumber = value;
                NotifyPropertyChanged("LeftNumber");
            }
        }
    

    等等

    【讨论】:

    • 您的代码不是 100% 正确,但我已修复,我现在有另一个问题,我在 TextBox 中看不到结果,据我所知,它的边界是正确的,我可以得到它在 MessageBox 上的值,但我在 TextBox 上看不到它。这与我的 VM 中 Result DP 的数据类型有关吗?我也尝试使用 ValueConverter 但仍然无法正常工作:(
    • @Stacked:我想知道代码有什么问题?如果你告诉我,我会更正答案,这样其他读者就不需要自己更正了。
    • @Stacked:奇怪,绑定应该可以工作。您确定数据上下文是正确的吗?顺便说一句,您的 Result DP 的类型是什么?也许你可以发布VM​​类。
    • @Stacked try
    • @Vlad 你不应该实现 INotifyPropertyChanged 以便绑定知道 Result 已更新吗?
    【解决方案2】:

    谢谢大家,尤其是@Vlad。只是一个小错误,你已经在class CalcViewModel : DependencyObject 上两次声明了属性Result

    现在可以正常使用了 :)

    【讨论】:

    • 哦,我明白了。我已经删除了多余的属性。谢谢!
    猜你喜欢
    • 2010-11-04
    • 1970-01-01
    • 2012-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-05
    • 2012-02-23
    相关资源
    最近更新 更多