【问题标题】:PropertyChanged event null after setting DataContext设置 DataContext 后 PropertyChanged 事件为空
【发布时间】:2012-08-09 00:13:58
【问题描述】:

我在 View 的构造函数中将我的 View 的 DataContext 设置为我的 ViewModel 的一个实例,只是标准的东西。此后不久,UPDATE_RECENT_DOCUMENTS_LIST 事件从我的 ViewModel 正确捕获的事件聚合器中触发。更改了属性并调用了 onPropertyChanged 方法,但由于 PropertyChanged 事件为空而失败。

接下来我要做的是对 UI 执行一个操作,它会引发一个 CREATE_PROJECT 事件,并且同一个 ViewModel 正在接收事件,除了现在,PropertyChanged 事件不再为空,一切都按预期工作.

在设置 DataContext 之后,在它注册到 PropertyChanged 事件之前是否需要经过特定的时间量?是否有一个我可以等待的事件来确保 PropertyChanged 事件不为空?

此外,在集成 Prism 并使用非常方便的 EventAggregator 之后,我没有使用标准 .NET 事件遇到这个问题。

我在 View 和 ViewModel 后面显示我的代码,为简洁起见省略了 View XAML。

ToolBarView.xaml.cs:

namespace ToolBarModule
{   

public partial class ToolBarView : UserControl
    {                           
        public ToolBarView(ToolBarViewModel toolBarViewModel)
        {
            InitializeComponent();             
            this.DataContext = toolBarViewModel;                                
        }        
    }
}

ToolBarViewModel.cs

namespace ToolBarModule
{

public class ToolBarViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private ToolBarCommands baseCommands;
    private IEventAggregator eventAggregator;

    private KickStartEvent kickStartEvent;
    private SubscriptionToken subscriptionToken;

    private ObservableCollection<IDocumentReference> recentDocuments = new ObservableCollection<IDocumentReference>();

    private ActionCommand newTest;
    private ActionCommand openTest;
    private ActionCommand saveTest;        
    private ActionCommand exitApplication;

    public ToolBarViewModel(){}

    public ToolBarViewModel(IEventAggregator eventAggregator)
    {
        this.eventAggregator = eventAggregator;
        baseCommands = new ToolBarCommands(eventAggregator);
        kickStartEvent = eventAggregator.GetEvent<KickStartEvent>();
        subscriptionToken = kickStartEvent.Subscribe(kickStartEventHandler, ThreadOption.UIThread, true, toolBarEventHandlerFilter);            
    }

    public ICommand NewTest
    {
        get
        {
            if (newTest == null)
            {
                newTest = new ActionCommand(baseCommands.NewTestAction);
            }
            return newTest;
        }
    }

    public ICommand OpenTest
    {
        get
        {
            if (openTest == null)
            {
                openTest = new ActionCommand(baseCommands.OpenTestAction);
            }
            return openTest;
        }
    }

    public ICommand SaveTest
    {
        get
        {
            if (saveTest == null)
            {
                saveTest = new ActionCommand(baseCommands.SaveTestAction);
            }
            return saveTest;
        }
    }


    public ICommand ExitApplication
    {
        get
        {
            if (exitApplication == null)
            {
                exitApplication = new ActionCommand(baseCommands.ExitApplicationAction);
            }
            return exitApplication;
        }
    }

    public ObservableCollection<IDocumentReference> RecentDocuments
    {
        get
        {
            return recentDocuments;
        }

        set
        {
            recentDocuments = value;
            onPropertyChanged("RecentDocuments");
        }
    }

    private void onPropertyChanged(string propertyChanged)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this,new PropertyChangedEventArgs(propertyChanged));
        }

    }

    private void kickStartEventHandler(KickStartEventsArgs e)
    {
        switch (e.EventType)
        {
            case KickStartEventsArgs.KickStartEventType.CREATE_PROJECT:
                onPropertyChanged("RecentDocuments");
            break;                


            case KickStartEventsArgs.KickStartEventType.UPDATE_RECENT_DOCUMENTS_LIST:
            RecentDocuments.Clear();

            foreach (IDocumentReference recentDocs in e.KickStartTestList)
            {
                RecentDocuments.Add(recentDocs);
            }
            onPropertyChanged("RecentDocuments");
            break;
        }
    }
}

}

【问题讨论】:

  • 你在 XAML 中命名了你的 UserControl 吗?
  • 提供您的 UserControl 的 XAML。
  • 您是自己创建 ToolBarView 还是使用 Resolve 或 RegionManager ?....也许您需要等到控件已加载到 Visual 树中...即等到 Loaded 事件之后……如果您愿意,可以在 Loaded 事件中设置 DataContext
  • 感谢大家的cmets。 @colinsmith - 我确实尝试在我发布之前在加载的事件中设置 DataContext,但这并没有帮助。我还验证了事件在 DataContext 设置后触发,这让我相信实际绑定发生在 DataContext 命令之后 >t0。

标签: c# wpf prism datacontext propertychanged


【解决方案1】:

您还可以尝试在 UserControl 下方设置 Grid 或 Element 的 DataContext。对我来说它有效。

示例(如果您使用 DependencyProperty,不起作用):

代码背后:

public MyUserControl()
{
     InitializeComponent();
     this.DataContext = new { LabelText = "Hello World!" };
}

XAML

<UserControl x:Class="CoolProject.ViewModel.MyUserControl"
         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" 
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800">
<Label x:Name="myLabel" Content="{Binding LabelText}"/>

示例 2(我的工作代码):

代码背后:

public MyUserControl()
{
     InitializeComponent();
     this.myGrid.DataContext = new { LabelText = "Hello World!" };
}

XAML

<UserControl x:Class="CoolProject.ViewModel.MyUserControl"
         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" 
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800">

<Grid x:Name="myGrid">
    <Label x:Name="myLabel" Content="{Binding LabelText}"/>
</Grid>

【讨论】:

  • @satanTime 我加了一个!
【解决方案2】:

您必须在 XAML 中命名您的 UserControl 并在绑定中使用它。类似于以下代码:

<UserControl x:Name="uc" >
.
.
.
<TextBox Text="{Binding UserName, Mode=TwoWay, ElementName=uc}"/>

其中uc 是您的UserControl 的名称,并且还尝试在加载UserControl 时设置DataContext。

希望对您有所帮助。

【讨论】:

  • 我的UserControl没有命名,但是命名后PropertyChanged事件还是null。
  • 你设置了绑定的 ElementName 吗?
  • 我的所有绑定工作正常,只是在我的控件加载后 PropertyChanged 事件立即为空。我必须做的是延迟发送事件大约 500 毫秒,以便给 PropertyChanged 事件绑定时间,这解决了问题。感谢您对 Saber 的贡献!
猜你喜欢
  • 2011-10-20
  • 1970-01-01
  • 2010-10-11
  • 2010-12-03
  • 2015-01-01
  • 2019-03-26
  • 2021-10-31
  • 1970-01-01
  • 2020-05-11
相关资源
最近更新 更多