Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF绑定已启用到视图模型上的方法_C#_Wpf_Data Binding - Fatal编程技术网

C# WPF绑定已启用到视图模型上的方法

C# WPF绑定已启用到视图模型上的方法,c#,wpf,data-binding,C#,Wpf,Data Binding,我正在开发一个WPF应用程序,它使用声明来控制用户可以做什么和不可以做什么。要求禁用用户无权访问的控件。在我们的基本视图模型中,我们有以下方法: HasClaim(string name); HasClaim(字符串名称); 我想在视图中这样做: <button IsEnabled="{Binding HasClaim("NAME")}" /> 我知道我可以做ObjtDATA提供程序,但是我不想为每个请求创建一个。 如果你经常在你的视图中这样做,考虑使用标记扩展。最有可能的情况是,您不需要

我正在开发一个WPF应用程序,它使用声明来控制用户可以做什么和不可以做什么。要求禁用用户无权访问的控件。在我们的基本视图模型中,我们有以下方法:

HasClaim(string name); HasClaim(字符串名称); 我想在视图中这样做:

<button IsEnabled="{Binding HasClaim("NAME")}" />

我知道我可以做ObjtDATA提供程序,但是我不想为每个请求创建一个。

如果你经常在你的视图中这样做,考虑使用标记扩展。最有可能的情况是,您不需要来自视图或视图模型的任何信息来检查用户是否拥有正确的声明,通常这些信息是在登录时获取的,并且不依赖于具体的视图

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"/>
更新以在评论中回答您的问题。你可以这样做。假设某个简单的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;
    }
}

您可以使用多值转换器并将按钮本身及其DataContext作为绑定传递:

<Button Name="someName">
    <Button.IsEnabled>
        <MultiBinding Converter={StaticResource HasClaimConverter}>
            <Binding Path="Name" RelativeSource="{RelativeSource Self}"/>
            <Binding/>
        </MultiBinding>
    </Button.IsEnabled>
</Button>

您是如何创建按钮的。。。我们需要看到更多的代码…您只能绑定到属性,因此解决方案很简单:创建一个调用
HasClaim(“NAME”)
的属性并绑定到该属性。@mike z:如何从视图中调用带有参数的属性?…:-)我认为这是Monty描述的转换器。@Fruchtzwerg将视图中的其他参数绑定到属性。因此,视图模型具有
公共字符串名称{get;set;}公共字符串hasnamesclaim{get{return haslaim(Name);}}
。很明显,你想实现INPC以使更新生效,但我想你明白了。是的,我建议使用转换器,然后删除了注释。。。。希望看到更多的代码来演示如何使用转换器,而不是简单地抛出建议…太棒了!这就是我要找的,谢谢。一个问题。是否可以重新执行此操作?我问这个问题的原因是,在这个应用程序中,主窗口是在身份验证之前创建的,因此所有内容都将返回false。我更新了我的答案,并建议如何执行此操作。我希望我早一点看到这个答案。如果可以的话,我会给它更多的a+1。
<Button Name="someName">
    <Button.IsEnabled>
        <MultiBinding Converter={StaticResource HasClaimConverter}>
            <Binding Path="Name" RelativeSource="{RelativeSource Self}"/>
            <Binding/>
        </MultiBinding>
    </Button.IsEnabled>
</Button>
class HasClaimConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var name= values[0] as String;
        var vm = values[1] as YourViewModel;

        return YourViewModel.HasClaim(name);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}