C# 在另一个视图模型中更改了RaiseProperty
我有一个主视图模型C# 在另一个视图模型中更改了RaiseProperty,c#,wpf,mvvm,C#,Wpf,Mvvm,我有一个主视图模型 public class MainViewModel : ViewModelBase { public MenuViewModel MenuVM { get; set; } public StatusBarViewModel StatusBarVM {get; set; } } 每个子视图模型都具有绑定在视图上的属性: public class MenuViewModel { private string _property1; public
public class MainViewModel : ViewModelBase
{
public MenuViewModel MenuVM { get; set; }
public StatusBarViewModel StatusBarVM {get; set; }
}
每个子视图模型都具有绑定在视图上的属性:
public class MenuViewModel
{
private string _property1;
public string Property1
{
get { return _property1; }
}
}
及
我想做的是,当is Property2被更改时,引发属性更改以更新Property1
所以问题是Property1。当我更改Property2(我使用断点测试)时,Get
没有被调用
问题是:
为什么这不起作用?
如何做到这一点
谢谢:)记住!您不能从实例调用
RaisePropertyChanged()
,因为该方法在MVVM Light中受保护!因此,在您的菜单视图模型中制作一个包装:
public void RaiseProperty1Changed()
{
RaisePropertyChanged("Property1");
}
在您的MainViewModel
中,订阅StatusBarViewModel
中Property2
的事件RaisePropertyChanged
StatusBarVM.PropertyChanged += OnProperty2Changed
在此委托方法调用中:
private void OnProperty2Changed(object sender, PopertyChangedEventArgs e)
{
if (e.PropertyName == "Property2")
{
MenuVM.RaiseProperty1Changed();
}
}
由于其他答案显示了很好的解决方法,它们创建了对ViewModels的硬引用,或者检查了要更改的属性的名称,我发现这太复杂了,我建议您使用另一种方法来实现StatusBar
一个很好的方法是使用Messenger
模式,我在这里构建了一个示例库,它提供了StatusBar
UserControl,以及一个帮助类StatusManager
,它帮助StatusBar中的控件subscribe
进行更新,这允许外部对象向状态栏发送更新
订阅:
public static void Subscribe<TSubscriber, TMessage>(string token, Action<TMessage> subscriberAction)
{
_subscribers.Add(new Subscribtion<TSubscriber, TMessage>(subscriberAction, token));
}
public static void UpdateStatus<TSubscriber, TMessage>(object status, string token)
{
if (!(status.GetType() == typeof(TMessage)))
{
throw new ArgumentException("Message type is different than the second type argument");
}
var subscribersWithCorrespondingType = (from subscriber in _subscribers
where (subscriber.GetType().GenericTypeArguments[0] == typeof(TSubscriber)) &&
(subscriber.GetType().GenericTypeArguments[1] == typeof(TMessage))
select subscriber).ToList();
var subscribers = (from subscriber in subscribersWithCorrespondingType
where ((Subscribtion<TSubscriber, TMessage>) subscriber).Token == token
select subscriber).ToList();
foreach (var subscriber in subscribers)
{
((Subscribtion<TSubscriber, TMessage>)subscriber).SubscriberAction((TMessage)status);
}
}
更新时,它将如下所示:
private void Button_Click(object sender, RoutedEventArgs e)
{
StatusManager.UpdateStatus<Label, string>("StatusBar's label updated !!");
}
private void按钮\u单击(对象发送者,路由目标)
{
StatusManager.UpdateStatus(“状态栏的标签已更新!!”);
}
如您所见,这提供了更多的独立性和灵活性,我很高兴收到建议和更正 我想增强@Sebastian Richter解决方案,使其更通用,并告知酒店:
/// <summary>
/// Wrapper to Raise a Property name from outside this View Model
/// It's not possible to call RaisePropertyChanged(..) from outside in MVVM Light.
/// </summary>
/// <param name="propertyName"></param>
internal void OuterRaisePropertyChanged(string propertyName)
{
RaisePropertyChanged(propertyName);
}
请注意,使用nameof
关键字的优点是,当您使用VS IDE重命名属性名时,它将重命名包含RaisePropertyChanged参数的解决方案中的所有变量名
@我想这就是你在哪里寻找的
关于您需要为右视图模型实例调用它。例如,menuViewModelInstance.RaisePropertyChanged(“Property1”)代码>@Sinatr,它无法工作,因为从属性的另一个实例调用RaisePropertyChanged时,MVVMLight处理程序为null。然后它返回而不调用处理程序。参见代码:var handler=PropertyChanged;if(handler!=null){handler(this,newpropertychangedeventargs(propertyName));}好主意。在这种情况下,我将在MVVM灯中使用Messenger。但是在“创建硬引用”这一点上,什么是如此错误?@SebastianRichter这并不是“如此错误”,我只是发现它是某种耦合的,保持类(甚至是视图模型)解耦总是更好的,耦合更少的代码,更好的软件。
StatusManager.Subscribe<Label, string>((s) =>
{
lblCursorPosition.Content = s;
});
private void Button_Click(object sender, RoutedEventArgs e)
{
StatusManager.UpdateStatus<Label, string>("StatusBar's label updated !!");
}
/// <summary>
/// Wrapper to Raise a Property name from outside this View Model
/// It's not possible to call RaisePropertyChanged(..) from outside in MVVM Light.
/// </summary>
/// <param name="propertyName"></param>
internal void OuterRaisePropertyChanged(string propertyName)
{
RaisePropertyChanged(propertyName);
}
public class StatusBarViewModel
{
private string _property2;
public string Property2
{
get { return _property2; }
set
{
_property2 = value;
RaisePropertyChanged(nameof(Property2));
OuterRaisePropertyChanged(nameof(MenuVM.Property1));
}
}
}