另一个视图模型中的RaisePropertyChanged
本文关键字:RaisePropertyChanged 模型 视图 另一个 | 更新日期: 2023-09-27 18:04:06
我有一个主ViewModel
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; }
}
}
和
public class StatusBarViewModel
{
private string _property2;
public string Property2
{
get { return _property2; }
set
{
_property2 = value;
RaisePropertyChanged("Property2");
RaisePropertyChanged("Property1");
}
}
}
我想做的是,当Property2被改变时,引发property changed以便更新Property1。
所以问题是Property1.Get
不被调用时,我改变Property2(我测试了一个断点)。
问题是:
为什么不工作?如何做到这一点?
谢谢
记住!你不能从实例中调用RaisePropertyChanged()
,因为该方法在MVVM Light中受到保护!因此,在MenuViewModel
:
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();
}
}
public class MainViewModel : ViewModelBase
{
public MenuViewModel MenuVM { get; set; }
public StatusBarViewModel StatusBarVM { get; set; }
public MainViewModel()
{
MenuVM = new MenuViewModel();
StatusBarVM = new StatusBarViewModel();
StatusBarVM.PropertyChanged += (s, e) =>
{
if (e.PropertyName == "Property2" && MenuVM != null)
MenuVM.RaisePropertyChanged("Property1");
};
}
}
public class MenuViewModel : INotifyPropertyChanged
{
private string _property1;
public string Property1
{
get { return _property1; }
}
public event PropertyChangedEventHandler PropertyChanged;
internal void RaisePropertyChanged(string p)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(p));
}
}
public class StatusBarViewModel : INotifyPropertyChanged
{
private string _property2;
public string Property2
{
get { return _property2; }
set
{
_property2 = value;
RaisePropertyChanged("Property2");
}
}
private void RaisePropertyChanged(string p)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(p));
}
public event PropertyChangedEventHandler PropertyChanged;
}
由于其他答案显示了很好的解决方案,它们创建了对ViewModels的引用,或者检查要更改的属性的名称,我发现它们太耦合了,我建议您使用另一种方法来实现StatusBar。
一个好的方法是使用Messenger
模式,我在这里构建了一个示例库,它提供了一个StatusBar
UserControl,和一个Helper类StatusManager
,它帮助StatusBar内部的控件到Subsribe
进行更新,并允许外部对象将updates
发送到StatusBar
订阅:
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);
}
}
使用:
如果状态栏包含一个名为lblCursorPosition
的标签,它可以订阅类型为string
的更新:
StatusManager.Subscribe<Label, string>((s) =>
{
lblCursorPosition.Content = s;
});
和更新它看起来像这样:
private void Button_Click(object sender, RoutedEventArgs e)
{
StatusManager.UpdateStatus<Label, string>("StatusBar's label updated !!");
}
如您所见,这提供了更多的独立性和灵活性,我很高兴收到建议和更正。
我想增强@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);
}
然后从另一个Class实例调用它:
public class StatusBarViewModel
{
private string _property2;
public string Property2
{
get { return _property2; }
set
{
_property2 = value;
RaisePropertyChanged(nameof(Property2));
OuterRaisePropertyChanged(nameof(MenuVM.Property1));
}
}
}
请注意,使用nameof
关键字的好处是,当您使用VS IDE重命名属性名称时,它将重命名包含RaisePropertyChanged参数的解决方案中的所有变量名称。
@Epitouille,我想这就是你一直在寻找的东西。
对