如果您经常在视图中这样做,请考虑使用标记扩展。很可能您不需要来自视图或视图模型的任何信息来检查用户是否拥有正确的声明,通常此类信息是在登录时获取的,并且不依赖于具体视图。
public class HasClaimExtension : MarkupExtension {
private readonly string _name;
public HasClaimExtension(string name) {
_name = name;
}
public override object ProvideValue(IServiceProvider serviceProvider) {
return HasClaim();
}
private bool HasClaim() {
// check if user has this claim here
if (_name.ToLowerInvariant() == "admin")
return true;
return false;
}
}
那么就:
<Button IsEnabled="{local:HasClaim Admin}" Height="20" Width="100"/>
在不太可能的情况下,您确实需要访问您的视图模型,您仍然可以这样做:
public class HasClaimExtension : MarkupExtension {
private readonly string _name;
public HasClaimExtension(string name) {
_name = name;
}
public override object ProvideValue(IServiceProvider serviceProvider) {
var service = (IProvideValueTarget) serviceProvider.GetService(typeof (IProvideValueTarget));
// this is Button or whatever control you set IsEnabled of
var target = service.TargetObject as FrameworkElement;
if (target != null) {
// grab it's DataContext, that is your view model
var vm = target.DataContext as MyViewModel;
if (vm != null) {
return vm.HasClaim(_name);
}
}
return false;
}
}
public class MyViewModel {
public bool HasClaim(string claim) {
return false;
}
}
更新以在评论中回答您的问题。你可以这样做。假设一些简单的 LoginManager 类:
public class LoginManager {
public static LoginManager Instance = new LoginManager();
private LoginManager() {
}
public bool IsLoggedIn { get; private set; }
public void Login() {
// do something, then
IsLoggedIn = true;
OnLoggedIn?.Invoke();
}
public bool HasClaim(string name) {
if (!IsLoggedIn)
throw new Exception("Cannot check claim until logged in");
return true;
}
public event Action OnLoggedIn;
}
它有一些关于声明是否已经可用的指示,以及当这些声明可用时通知的事件,如果现在它们不可用。然后在您的标记扩展中,您首先检查声明是否在这里。如果是 - 只需返回结果。如果不是 - 返回 false,但在这些声明可用时订阅事件。之后 - 用实际值更新目标属性。
public class HasClaimExtension : MarkupExtension {
private readonly string _name;
public HasClaimExtension(string name) {
_name = name;
}
public override object ProvideValue(IServiceProvider serviceProvider) {
if (LoginManager.Instance.IsLoggedIn) {
return LoginManager.Instance.HasClaim(_name);
}
// if not logged in yet
var service = (IProvideValueTarget) serviceProvider.GetService(typeof (IProvideValueTarget));
var target = service.TargetObject as FrameworkElement;
// this is dependency property you want to set, IsEnabled in this case
var targetProperty = service.TargetProperty as DependencyProperty;
if (target != null && targetProperty != null) {
if (targetProperty.PropertyType != typeof (bool)) {
// not boolean property - throw
throw new Exception("HasClaim extension should be applied to Boolean properties only");
}
// here, subscribe to event after which your claims are available
LoginManager.Instance.OnLoggedIn += () => {
// update target property
if (Application.Current.Dispatcher.CheckAccess())
target.SetValue(targetProperty, LoginManager.Instance.HasClaim(_name));
else {
Application.Current.Dispatcher.Invoke(() => {
target.SetValue(targetProperty, LoginManager.Instance.HasClaim(_name));
});
}
};
}
return false;
}
}