使用 INotifyPropertyChanged 的​​ WPF 双向模式绑定不起作用

WPF two way mode binding using INotifyPropertyChanged not working

所以我面临一个棘手的问题。这是我的视图模型:

namespace Market.ViewModel
{
    public class BillingViewModel : ViewModelBase
    {
        #region Private Members

        private Customer _customer;
        private Product _products;
        private string _productId = "asd";
        RelayCommand _numClickedCommand;

        #endregion

        public Customer Customer
        {
            get { return _customer; }
            set
            {
                _customer = value;
                NotifyPropertyChanged("Customer");
            }
        }

        public Product Products
        {
            get { return _products; }
            set
            {
                _products = value;
                NotifyPropertyChanged("Products");
            }
        }

        public bool CanClick
        {
            get { return true; }
        }

        public string ProductId
        {
            get { return _productId; }
            set
            {
                _productId = value;
                NotifyPropertyChanged("ProductId");
            }
        }

        public ICommand NumClickedCommand
        {
            get
            {
                if (_numClickedCommand == null)
                {
                    _numClickedCommand = new RelayCommand(param => this.NumClicked(param.ToString()),
                        param => this.CanClick);
                }
                return _numClickedCommand;
            }
        }

        #region PrivateMethods

        private void NumClicked(string numClicked)
        {
            ProductId = ProductId+numClicked;
        }

        #endregion
    }
}

它继承了实现INotifyPropertyCanged的ViewModelBase。

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

我的观点是:

<Window x:Class="Billing.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:controls="clr-namespace:Billing"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:viewModel="clr-namespace:Market.ViewModel;assembly=Market.ViewModel"
    xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
    Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <viewModel:BillingViewModel x:Key="ViewModel" />
    </Window.Resources>
    <Grid DataContext="{Binding Source={StaticResource ViewModel}}">
        <controls:NumPad HorizontalAlignment="Left" Margin="265,205,0,-192" VerticalAlignment="Top" Height="307" Width="242"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="247,29,0,0" TextWrapping="Wrap" Text="{Binding ProductId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
    </Grid>
</Window>

NumClickedCommand 用于此 xaml:

<UserControl x:Class="Billing.NumPad"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:viewModel="clr-namespace:Market.ViewModel;assembly=Market.ViewModel"
         mc:Ignorable="d" Height="109" Width="248">

    <UserControl.Resources>
        <viewModel:BillingViewModel x:Key="ViewModel"/>
    </UserControl.Resources>
    <Grid Height="109" VerticalAlignment="Top" DataContext="{Binding Source={StaticResource ViewModel}}">
        <Button Content="1" HorizontalAlignment="Left" Margin="10,0,0,0" VerticalAlignment="Top" Width="75" CommandParameter="1" Command="{Binding NumClickedCommand}"/>
        <Button Content="2" HorizontalAlignment="Left" Margin="90,0,0,0" VerticalAlignment="Top" Width="75" CommandParameter="2" Command="{Binding NumClickedCommand}"/>
        <Button Content="3" HorizontalAlignment="Left" Margin="170,0,0,0" VerticalAlignment="Top" Width="75" CommandParameter="3" Command="{Binding NumClickedCommand}"/>
        <Button Content="4" HorizontalAlignment="Left" Margin="10,27,0,0" VerticalAlignment="Top" Width="75" CommandParameter="4" Command="{Binding NumClickedCommand}"/>
        <Button Content="5" HorizontalAlignment="Left" Margin="90,27,0,0" VerticalAlignment="Top" Width="75" CommandParameter="5" Command="{Binding NumClickedCommand}"/>
        <Button Content="6" HorizontalAlignment="Left" Margin="170,27,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="1.034,2.171" CommandParameter="6" Command="{Binding NumClickedCommand}"/>
        <Button Content="7" HorizontalAlignment="Left" Margin="10,54,0,0" VerticalAlignment="Top" Width="75" CommandParameter="7" Command="{Binding NumClickedCommand}"/>
        <Button Content="8" HorizontalAlignment="Left" Margin="90,54,0,0" VerticalAlignment="Top" Width="75" CommandParameter="8" Command="{Binding NumClickedCommand}"/>
        <Button Content="9" HorizontalAlignment="Left" Margin="170,54,0,0" VerticalAlignment="Top" Width="75" CommandParameter="9" Command="{Binding NumClickedCommand}"/>
        <Button Content="0" HorizontalAlignment="Left" Margin="10,81,0,0" VerticalAlignment="Top" Width="75"  CommandParameter="0" Command="{Binding NumClickedCommand}"/>
        <Button Content="Submit" HorizontalAlignment="Left" Margin="90,81,0,0" VerticalAlignment="Top" Width="155" />

    </Grid>
</UserControl>

问题是在视图模型中更新 ProductId 不会反映在视图中。 asd 的初始值在应用程序启动时更新。这些控件包含一组实现 ICommand 接口的按钮,它们都调用视图模型中的 NumClicked()。在调试时,如果我单击按钮 NumClicked() 被调用然后 ProductId 被更新并且 NotifyPropertyChanged() 也被调用但 UI 不更新,它保持不变。但是如果我直接更新 UI 即我在文本框中输入一些值,同样的流程会发生,PropertyChanged() 被调用,之后也调用 get 来更新视图模型中的值。

我已经回答了很多这样的问题,但无法弄清楚到底是什么阻止了 UI 的更新。感谢任何帮助,并询问是否缺少任何东西。 谢谢。

GridTextBox

DataContext 绑定到来自 Window 资源的视图模型实例。

NumPad 控件声明了它自己的视图模型实例

NumClickedCommand 使用错误的数据,而不是显示的对象

确保只有一个视图模型实例

NumPad 继承 DataContext 并且不应创建新对象并更改 DataContext

<UserControl x:Class="Billing.NumPad"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:viewModel="clr-namespace:Market.ViewModel;assembly=Market.ViewModel"
         mc:Ignorable="d" Height="109" Width="248">

<Grid Height="109" VerticalAlignment="Top">
    <!--all Buttons here-->    
</Grid>

您将相同的视图模型传递给 numpadUser 控件和 mainWindow 也作为 DataContext,因此这将创建视图模型的新实例,因此根据我的说法,您可以在 NumPad 中使用 mainwindow 的 DataContext,也可以使用 Minwindow 的 GridName,您必须命名您的网格喜欢

<Grid DataContext="{Binding Source={StaticResource ViewModel}}" x:Name="grdNumPad">

并且您可以通过这种方式NumPad.XAML访问您的 DataContext

<Button Content="1" HorizontalAlignment="Left" Margin="10,0,0,0" VerticalAlignment="Top" Width="75" CommandParameter="1" Command="{Binding DataContext.NumClickedCommand,ElementName=grdNumPad}"/>