简体   繁体   English

如何使用 PRISM 在 WPF 中导航并绑定 DataContext

[英]How to navigate in WPF using PRISM and bind DataContext

There must be a lot of questions surrounding this area but I couldn't find anything to help in my instance.这个领域肯定有很多问题,但在我的例子中我找不到任何帮助。

The problem I'm experiencing is getting my ViewModel, and specifically a property within ViewModel, to be updated to my View.我遇到的问题是让我的 ViewModel,特别是 ViewModel 中的一个属性更新到我的视图。 Below is my implementation.下面是我的实现。 I think I understand where I'm going wrong but not sure how to resolve it.我想我明白我哪里出错了,但不知道如何解决。

I have a Module that has a list and edit view.我有一个具有列表和编辑视图的模块。 Quite simply lists domain objects and then ability to edit a domain object.非常简单地列出域对象,然后能够编辑域对象。

My xaml binds the DataContent to a ViewModel property in my View.我的 xaml 将 DataContent 绑定到我的视图中的 ViewModel 属性。

I then use the INavigationAware.NavigateTo method to navigate to my ViewModel and this is where I load the domain object.然后我使用 INavigationAware.NavigateTo 方法导航到我的 ViewModel,这是我加载域对象的地方。

The problem is that obviously this is not reflected back to the View.问题是,显然这并没有反映回视图。 The view already has an instance of the ViewModel.该视图已经有一个 ViewModel 的实例。 This method worked fine when the ViewModel was using a list of objects using ObservableCollection.当 ViewModel 使用 ObservableCollection 使用对象列表时,此方法运行良好。 However, this did not work when using a simple object or even an ObservableObject.但是,这在使用简单对象甚至 ObservableObject 时不起作用。

Could someone please help my understanding or point me to some links with a better implementation of what I am trying to achieve?有人可以帮助我理解或指出一些可以更好地实现我想要实现的目标的链接吗?

MyModule我的模块

public class MyModule : IModule
{
    private readonly IRegionManager _regionManager;

    public MyModule(IRegionManager regionManager)
    {
        _regionManager = regionManager;
    }

    public void Initialize()
    {
        _regionManager.RegisterViewWithRegion(Constants.MainRegionName, typeof(MyListView));
        _regionManager.RegisterViewWithRegion(Constants.MainRegionName, typeof(MyEditView));
    }
}

XAML XAML

<UserControl
    DataContext="ViewModel">
    ...
    <TextBlock Text="{Binding Path=MyDomainObject.AProperty}" />
    ...

View看法

public partial class MyEditView
{
    public readonly static string ViewName = "MyEditView";

    public MyEditView(MyEditViewModel viewModel)
    {
        InitializeComponent();
        ViewModel = viewModel;
    }

    public MyEditViewModel ViewModel
    {
        get { return DataContext as MyEditViewModel; }
        private set { DataContext = value; }
    }
}

ViewModel视图模型

public class MyViewModel : INavigationAware
{
    private readonly IRegionManager _regionManager;

    public MyDomainObject MyDomainObject { get; set; }

    public void Load(ViewModelKey key)
    {
        // get domain object
        // this method worked when MyDomainObject was 
        // ObservableCollection<T> as just adding elements to list
        // where this is creating a new instance of MyDomainObject
        var id = parameter from navigationContext;
        MyDomainObejct = server.GetDomainObject(id);
    }

    public void OnNavigatedTo(NavigationContext navigationContext)
    {
        var key = key from navigationContext;
        Load(key);
    }
}

SOLUTION解决方案

public class MyEditViewModel : INavigationAware
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private MyDomainObject _myDomainObject;
    public MyDomainObject MyDomainObject
    {
        get
        {
            return _myDomainObject;
        }
        set
        {
            if (value != _myDomainObject)
            {
                _myDomainObject = value;
                NotifyPropertyChanged();
            }
        }
    }

View看法

public partial class MyEditView
{
    public MyEditView(MyEditViewModel viewModel)
    {
        InitializeComponent();
        ViewModel = viewModel;

        ViewModel.PropertyChanged += ViewModel_PropertyChanged;
    }

    public MyEditViewModel ViewModel
    {
        get { return DataContext as MyEditViewModel; }
        private set { DataContext = value; }
    }

    private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (!(sender is MyEditViewModel))
            return;

        ViewModel = (MyEditViewModel)sender;
    }
}

For your binding to update you need to implement INotifyPropertyChanged and raise PropertyChanged Event on the set accessor of your domain object.为了更新绑定,您需要实现INotifyPropertyChanged并在域对象的 set 访问器上引发 PropertyChanged 事件。

public event PropertyChangedEventHandler PropertyChanged = delegate {};


public MyDomainObject MyDomainObject
{
    get
    {
        return myDomainObject;
    }
    set
    {
        if(value != myDomainObject)
        {
            myDomainObject = value;
            RaisePropertyChanged("MyDomainObject");
        }
    }
}

private void RaisePropertyChanged(String p)
{
    PropertyChanged(this, new PropertyChangedEventArgs(p));
}

Or as in the Prism book, inherit NotificationObject and call RaisePropertyChanged(()=> PropertyName) which is refactoring-safe或者在 Prism 书中,继承 NotificationObject 并调用 RaisePropertyChanged(()=> PropertyName) 这是重构安全的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM