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));
        } 
    }
}