PropertyChanged仅在第一个事件上为null

时间:2015-01-07 20:06:23

标签: c# wpf asynchronous

我正准备在WPF中编写代码。所以我提出了一些基本的模拟代码,以便让自己继续前进。我有一个简单的WPF界面,我有一个日期选择器,一些文本框和复选框。

我想用INotifyPropertyChanged界面做的是,当我点击按钮时,我的文本框只会显示" Hello Kevin"。为了测试它,我开始说我的字符串将以&#34开始;最初"当我的方法返回时,它将返回" Hello Kevin"。

我还应该指定我做了一个模拟异步代码,它会调用服务器并获取数据库中的名称。这段代码工作得很好。事情是,当我第一次点击按钮时,PropretyChanged首先为空。但是,当我再次点击它时,它会显示我想要看到的消息。

让我想知道这个方法是否真的像我打算那样工作,所以我用Console.WriteLine方法进行了一些基本的测试,它只是向我显示我目前正在寻找的结果。

下面,你可以找到我用于这个小螺柱软件的所有类:

public class ViewModelCommonBase : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }
 }

public class SimpleViewModel : ViewModelCommonBase
{
    #region fields
    private bool _isHealthCareEnabled=false;

    private bool _isBenefits=false;

    private bool _is401kEnabled=false;

    private DateTime _birth;

    #endregion

    #region Properties

    public int Age
    {
        get { return  (int)((DateTime.Now - Birth).TotalDays)/365 ;}

    }
    public bool IsHealthCareEnabled
    {
        get { return _isHealthCareEnabled; }
        set { _isHealthCareEnabled = value; }
    }


    public bool IsBenefitsEnabled
    {
        get { return _isBenefits; }
        set
        {
            if (_isBenefits != value)
            {
                _isBenefits = value;
                OnPropertyChanged("IsBenefitsEnabled");
            }
        }
    }

    public bool Is401kEnabled
    {
        get { return _is401kEnabled; }
        set { _is401kEnabled = value; }
    }


    public DateTime Birth
    {
        get { return _birth; }
        set
        {
            if (_birth != value)
            {
                _birth = value;
                OnPropertyChanged("Birth");
                OnPropertyChanged("Age"); 
            }
        }
    }

    #endregion      
}

public class AsyncServerStud :ViewModelCommonBase
{
    private string _nameOfPerson="Initial";

    public string NameOfPerson
    {
        get { return _nameOfPerson; }
        set
        {
            if (_nameOfPerson != value)
            {
                _nameOfPerson = value;
                OnPropertyChanged("NameOfPerson");

            }
        }
    }


    public async void FindNameOfPerson()
    {
        var result = await FindNameOfPersonAsync("Kevin");
        NameOfPerson = result;
        Console.WriteLine(NameOfPerson);
    }

    private Task<string> FindNameOfPersonAsync(string name)
    {
        return Task.Factory.StartNew(() => SearchNameOfPerson(name));
    }

    private string SearchNameOfPerson(string name)
    {
        Thread.Sleep(6000);
        return "Hello, " + name;
    }


}

    public class WPFViewModelPage
{
    public SimpleViewModel SimpleViewModel { get; set; }
    public AsyncServerStud MockServer { get; set; }


}

这是我用于所有数据绑定和用户界面的XAML

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
    <!--<vm:SimpleViewModel x:Key="viewModel"/>--> 
        <vm:WPFViewModelPage x:Key="viewModel"/>
    </Window.Resources>
    <Grid Name="myGrid" DataContext="{Binding Source={StaticResource viewModel}}">
        <CheckBox x:Name="chkBenefits"
                  Content="Has Benefits ?"
                  HorizontalAlignment="Left" 
                  Margin="62,45,0,0"
                  VerticalAlignment="Top"
                  IsChecked="{Binding SimpleViewModel.IsBenefitsEnabled}"/>
        <StackPanel IsEnabled="{Binding SimpleViewModel.IsBenefitsEnabled}">
            <CheckBox Content="Health care" 
                  HorizontalAlignment="Left" 
                  Margin="85,86,0,0"
                  VerticalAlignment="Top"
                  IsEnabled="{Binding SimpleViewModel.IsBenefitsEnabled}"
                  IsChecked="{Binding SimpleViewModel.IsHealthCareEnabled}"/>
            <DatePicker Name="mydatePicker" DisplayDate="{Binding SimpleViewModel.Birth}"/>
            <TextBlock TextWrapping="Wrap" Text="{Binding SimpleViewModel.Age}"/>
            <Button Content="Button" Click="Button_Click_1"/>
            <TextBox Name="mySecondTextBox" Height="23" TextWrapping="Wrap" Text="{Binding MockServer.NameOfPerson }"/>
        </StackPanel>


    </Grid>
</Window>

当我删除xaml中的datacontext引用并将其放在页面后面的代码中时(我知道UI中不应该有任何后面的代码但是请耐心等待它)。这对我来说是一些非常奇怪的东西。一件事怎么可能坏,但另一件好事?

这里是新代码

public WPFViewModelPage ViewModel { get; set; }

    public MainWindow()
    {
        InitializeComponent();


        ViewModel = new WPFViewModelPage()
        {
            SimpleViewModel = new SimpleViewModel(),
            MockServer = new AsyncServerStud()
        };

        this.DataContext = ViewModel;
    }

    private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
    {

    }



    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        ViewModel.MockServer.FindNameOfPerson();
    }

1 个答案:

答案 0 :(得分:2)

我已对您的应用程序进行了以下更改,它对我有用。请尝试以下更改

DataContext分配给Window,而不是将其设置为Grid

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:WpfApplication1"
        Title="MainWindow"
        Height="350"
        Width="525">
    <Window.DataContext>
        <vm:WPFViewModelPage />
    </Window.DataContext>
    <Window.Resources>
        <vm:WPFViewModelPage x:Key="viewModel" />
    </Window.Resources>
    <Grid Name="myGrid">
        <CheckBox x:Name="chkBenefits"
                  Content="Has Benefits ?"
                  HorizontalAlignment="Left"
                  Margin="62,45,0,0"
                  VerticalAlignment="Top"
                  IsChecked="{Binding SimpleViewModel.IsBenefitsEnabled}" />
        <StackPanel IsEnabled="{Binding SimpleViewModel.IsBenefitsEnabled}">
            <CheckBox Content="Health care"
                      HorizontalAlignment="Left"
                      Margin="85,86,0,0"
                      VerticalAlignment="Top"
                      IsEnabled="{Binding SimpleViewModel.IsBenefitsEnabled}"
                      IsChecked="{Binding SimpleViewModel.IsHealthCareEnabled}" />
            <DatePicker Name="mydatePicker"
                        DisplayDate="{Binding SimpleViewModel.Birth}" />
            <TextBlock TextWrapping="Wrap"
                       Text="{Binding SimpleViewModel.Age}" />
            <Button Content="Button"
                    Click="Button_Click" />
            <TextBox Name="mySecondTextBox"
                     Height="23"
                     TextWrapping="Wrap"
                     Text="{Binding MockServer.NameOfPerson }" />
        </StackPanel>
    </Grid>
</Window>

修改WPFViewModelPage,如下所示

    public class WPFViewModelPage
    {
        public SimpleViewModel SimpleViewModel { get; set; }
        public AsyncServerStud MockServer { get; set; }

        public WPFViewModelPage()
        {
            this.SimpleViewModel = new SimpleViewModel();
            this.MockServer = new AsyncServerStud();
        }
    }

Button_Click方法

中添加以下代码
private void Button_Click(object sender, RoutedEventArgs e)
{
    WPFViewModelPage dataContext = this.DataContext as WPFViewModelPage;
    dataContext.MockServer.FindNameOfPerson();
}