C# 基于视图模型中的属性更改更新UI

C# 基于视图模型中的属性更改更新UI,c#,.net,wpf,C#,.net,Wpf,我是WPF的新手,所以这里可能缺少一些基本的东西。我有一个如下所示的应用程序: <Window x:Class="MyApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Test Application" Height="647" W

我是WPF的新手,所以这里可能缺少一些基本的东西。我有一个如下所示的应用程序:

<Window x:Class="MyApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test Application" Height="647" Width="723" Background="#88B0FF">

    <DockPanel Name="MainDock">
        <Button DockPanel.Dock="Top" Margin="5,0,5,0" x:Name="PingButton" Click="PingButton_OnClick">Ping</Button>
        <TextBox Text="{Binding Path=Output}" />
    </DockPanel>
</Window>
public partial class MainWindow : Window
{
    private Model _applicationModel = new Model();
    public Model ApplicationModel {
        get { return _applicationModel; }
        set { _applicationModel = value; }
    }

    public MainWindow()
    {
        InitializeComponent();

        this.DataContext = ApplicationModel;
        ApplicationModel.Output = "Not clicked";
    }

    private void PingButton_OnClick(object sender, RoutedEventArgs e)
    {
        ApplicationModel.Output = "Clicked";
    }
}
private string output;
public string Output
{
    get { return output; }
    set { SetProperty(ref output, value); }
}
我有一个名为Model的小类,它实现了INotifyPropertyChanged

public class Model : INotifyPropertyChanged
{

    public string Output { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
我运行此应用程序,文本框显示未单击的文本。当我点击按钮时,我希望文本会改变。事实并非如此。ApplicationModel对象被更新,这反映在DataContext中;然而,我在OnPropertyChanged方法中有一个断点,似乎从未调用过它

我做错了什么?

没有调用OnPropertyChanged,因为您没有调用它。 没有什么特殊的魔法可以将调用连接到OnPropertyChanged本身,所以您需要自己完成

具体地说,您应该修改输出属性,以便在其发生更改时调用它,并且对ApplicationModel属性执行相同操作不会造成任何伤害:

private string output;
public string Output
{
    get { return output; }
    set
    {
        if (output != value)
        {
            output = value;
            OnPropertyChanged("Output");
        }
    }
}
如果你的目标是.NET4.5,你可以利用减少样板代码;说明如何执行此操作。然后你会有这样的东西:

<Window x:Class="MyApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test Application" Height="647" Width="723" Background="#88B0FF">

    <DockPanel Name="MainDock">
        <Button DockPanel.Dock="Top" Margin="5,0,5,0" x:Name="PingButton" Click="PingButton_OnClick">Ping</Button>
        <TextBox Text="{Binding Path=Output}" />
    </DockPanel>
</Window>
public partial class MainWindow : Window
{
    private Model _applicationModel = new Model();
    public Model ApplicationModel {
        get { return _applicationModel; }
        set { _applicationModel = value; }
    }

    public MainWindow()
    {
        InitializeComponent();

        this.DataContext = ApplicationModel;
        ApplicationModel.Output = "Not clicked";
    }

    private void PingButton_OnClick(object sender, RoutedEventArgs e)
    {
        ApplicationModel.Output = "Clicked";
    }
}
private string output;
public string Output
{
    get { return output; }
    set { SetProperty(ref output, value); }
}

如果您使用的是.NET 4.0或更低版本,您可以使用表达式树,如前所述。

Bah,我希望这里有一些反射魔法。这里有减少样板文件的最佳实践吗?不喜欢[CallerMemberName],因为如果您需要通知与所调用的不同的属性,它将不起作用。代码最终将成为这两种方式的混合体。