我有一个主要的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被更改时,提升属性已更改以更新Property1。
因此,当我更改Property2(我使用断点测试)时,问题是Property1.Get
未被调用。
问题是:
为什么这不起作用? 如何让这个工作?
谢谢:)
答案 0 :(得分:3)
记住!您无法从实例调用RaisePropertyChanged()
,因为该方法在MVVM Light中受到保护!所以在MenuViewModel
:
public void RaiseProperty1Changed()
{
RaisePropertyChanged("Property1");
}
在MainViewModel
订阅RaisePropertyChanged
中Property2
的活动StatusBarViewModel
。{/ p>
StatusBarVM.PropertyChanged += OnProperty2Changed
在这个委托方法中调用:
private void OnProperty2Changed(object sender, PopertyChangedEventArgs e)
{
if (e.PropertyName == "Property2")
{
MenuVM.RaiseProperty1Changed();
}
}
答案 1 :(得分:1)
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;
}
答案 2 :(得分:0)
由于其他答案显示了很好的解决方法,他们创建了对ViewModel的硬引用,或检查要更改的属性的名称,并且我发现太多耦合,我建议您使用另一种方法来实现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);
}
}
使用:
如果StatusBar包含名为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 !!");
}
正如您所看到的,这提供了更多的独立性和灵活性,我很高兴收到建议和更正。
答案 3 :(得分:0)
我想通过要通知的属性来增强@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,我想这就是您要搜索的地方。
致谢