Link 来自不同 ViewModel 的 Xamarin 属性
Link Xamarin properties from different ViewModels
是否可以仅 "link" 不同 ViewModel 的两个属性,以便当一个 属性 更改时,另一个也会更改。所以本质上,我希望不同 ViewModel 中的两个属性表现得好像它们是一个一样。
如果我能在我的 ViewModel 中做类似下面的事情就好了:
WhenPropertyChanges(() => SettingX).CopyValueTo(() => ModelView2.SettingX);
示例:在我的设置页面上,当我更改设置时,我希望新值在另一个页面的 ViewModel 中可用。
我知道我可以用第三层(模型)实现它,但感觉有点笨拙,而且我现在解决它的方式感觉不对(触发事件)。
我从这个页面实现了以下 MVVM 模式:http://www.wintellect.com/devcenter/krome/linking-property-change-notifications-in-xamarin-forms-or-wpfsilverlight。据我所知,作者说他的代码使之成为可能,但不幸的是他没有说明如何实现。
我也找到了这篇文章 (http://blog.alectucker.com/post/2014/07/26/using-messageingcenter-in-xamarin-forms-for-viewmodel-to-viewmodel-navigation.aspx),但我不一定要导航到其他视图。尽管如此,也许我可以通过某种方式使用此 MessagingCenter 来实现我的目标?
我认为如果导航是线性的(你只需要第 2 页的第 1 页的信息),你可以使用 MessagingCenter 来做你想做的。
如果用户能够更改页面 2 中的数据(并在页面 1 中进行更新),则 messagingCenter 使用起来有点棘手。我认为您可以使用您提供的第一个 link。只需对 ViewModel 中的所有共享数据使用抽象 class。
如果您需要更多帮助,请提供更完整的代码示例。
这在您引用的我文章的最后一段中得到解决。我使用一个简单的扩展方法来做到这一点。可以在本文的源代码示例中看到一个示例,在这个文件中:https://github.com/Wintellect/XamarinSamples/blob/master/PropertyDependencyDemo%2FPropertyDependencyDemo%2FMvvm%2FObservableExtensions.cs
对于您的具体示例,它看起来像这样:
// using PropertyDependencyDemo.Mvvm;
// ... use the namespace above that contains the ObservableExtensions class
ModelView1
.WhenPropertyChanges((a) => a.SettingX)
.AlsoInvokeAction(() => ModelView2.SettingX = ModelView1.SettingX);
所有这一切都是以名称安全的方式为您连接到源视图模型的 PropertyChanged 事件。
请注意:您需要注意不要造成无意中阻止对象被垃圾回收的情况。发生这种情况的原因是,在此示例中,ViewModel1 现在将有一个引用 PropertyDependency 对象的 PropertyChanged 处理程序,由于在 Action lambda 表达式中捕获了引用,该对象又引用了 ModelView1 和 ModelView2。
如果您确定这不会成为问题(也许两者一起超出范围),则无需担心。但是,如果您发现自己面临需要阻止 ModelView1 保持 ModelView2 固定的情况,那么您可以使用 WeakReference 来实现。同样,这不太可能成为问题,但如果您发现它泄漏内存,则可以将上面的内容更改为:
// assuming "TModelView" is the class name of the viewmodels
var wr = new WeakReference<TModelView>(ModelView2);
ModelView1
.WhenPropertyChanges((a) => a.SettingX)
.AlsoInvokeAction(() => {
TModelView mv;
if (wr.TryGetTarget(out mv))
mv.SettingX = ModelView1.SettingX;
});
是否可以仅 "link" 不同 ViewModel 的两个属性,以便当一个 属性 更改时,另一个也会更改。所以本质上,我希望不同 ViewModel 中的两个属性表现得好像它们是一个一样。
如果我能在我的 ViewModel 中做类似下面的事情就好了:
WhenPropertyChanges(() => SettingX).CopyValueTo(() => ModelView2.SettingX);
示例:在我的设置页面上,当我更改设置时,我希望新值在另一个页面的 ViewModel 中可用。
我知道我可以用第三层(模型)实现它,但感觉有点笨拙,而且我现在解决它的方式感觉不对(触发事件)。
我从这个页面实现了以下 MVVM 模式:http://www.wintellect.com/devcenter/krome/linking-property-change-notifications-in-xamarin-forms-or-wpfsilverlight。据我所知,作者说他的代码使之成为可能,但不幸的是他没有说明如何实现。
我也找到了这篇文章 (http://blog.alectucker.com/post/2014/07/26/using-messageingcenter-in-xamarin-forms-for-viewmodel-to-viewmodel-navigation.aspx),但我不一定要导航到其他视图。尽管如此,也许我可以通过某种方式使用此 MessagingCenter 来实现我的目标?
我认为如果导航是线性的(你只需要第 2 页的第 1 页的信息),你可以使用 MessagingCenter 来做你想做的。
如果用户能够更改页面 2 中的数据(并在页面 1 中进行更新),则 messagingCenter 使用起来有点棘手。我认为您可以使用您提供的第一个 link。只需对 ViewModel 中的所有共享数据使用抽象 class。
如果您需要更多帮助,请提供更完整的代码示例。
这在您引用的我文章的最后一段中得到解决。我使用一个简单的扩展方法来做到这一点。可以在本文的源代码示例中看到一个示例,在这个文件中:https://github.com/Wintellect/XamarinSamples/blob/master/PropertyDependencyDemo%2FPropertyDependencyDemo%2FMvvm%2FObservableExtensions.cs
对于您的具体示例,它看起来像这样:
// using PropertyDependencyDemo.Mvvm;
// ... use the namespace above that contains the ObservableExtensions class
ModelView1
.WhenPropertyChanges((a) => a.SettingX)
.AlsoInvokeAction(() => ModelView2.SettingX = ModelView1.SettingX);
所有这一切都是以名称安全的方式为您连接到源视图模型的 PropertyChanged 事件。
请注意:您需要注意不要造成无意中阻止对象被垃圾回收的情况。发生这种情况的原因是,在此示例中,ViewModel1 现在将有一个引用 PropertyDependency 对象的 PropertyChanged 处理程序,由于在 Action lambda 表达式中捕获了引用,该对象又引用了 ModelView1 和 ModelView2。
如果您确定这不会成为问题(也许两者一起超出范围),则无需担心。但是,如果您发现自己面临需要阻止 ModelView1 保持 ModelView2 固定的情况,那么您可以使用 WeakReference 来实现。同样,这不太可能成为问题,但如果您发现它泄漏内存,则可以将上面的内容更改为:
// assuming "TModelView" is the class name of the viewmodels
var wr = new WeakReference<TModelView>(ModelView2);
ModelView1
.WhenPropertyChanges((a) => a.SettingX)
.AlsoInvokeAction(() => {
TModelView mv;
if (wr.TryGetTarget(out mv))
mv.SettingX = ModelView1.SettingX;
});