Wpf 如何将视图模型方法的结果绑定到TextBox属性?

Wpf 如何将视图模型方法的结果绑定到TextBox属性?,wpf,xaml,data-binding,methods,markup-extensions,Wpf,Xaml,Data Binding,Methods,Markup Extensions,在我的视图模型和模型中,我有一个签名为bool IsPropertyReadOnly(string propertyName)的方法。此方法确定当前登录的用户是否可以编辑属性值。少数用户将能够编辑属性值,而其他大多数用户将具有只读访问权限 我希望将IsPropertyReadOny的结果绑定到TextBox.IsReadOnly属性,而不是创建属性来返回每个模型属性的只读状态 以下是我对语法的设想: <TextBox Text="{Binding Address, Mode=TwoWay}

在我的视图模型和模型中,我有一个签名为
bool IsPropertyReadOnly(string propertyName)
的方法。此方法确定当前登录的用户是否可以编辑属性值。少数用户将能够编辑属性值,而其他大多数用户将具有只读访问权限

我希望将
IsPropertyReadOny
的结果绑定到
TextBox.IsReadOnly
属性,而不是创建属性来返回每个模型属性的只读状态

以下是我对语法的设想:

<TextBox Text="{Binding Address, Mode=TwoWay}" 
         IsReadOnly="{Binding MethodName=IsPropertyReadOnly MethodParameter=Address}"
/>

DataContext
包含视图模型,因此基本上我需要将
IsReadOnly
绑定到调用的结果
((类)this.DataContext)。IsPropertyReadOnly(“地址”)

使用
ObjectDataProvider
有很多文档,但是对象数据提供程序创建了一个新的对象实例,这不是我想要的。此外,要使用现有实例,我必须在代码隐藏中进行赋值。再说一次,不是我想做的

根据我的研究,从
Binding
MarkupExtension
继承的解决方案似乎更适合我的需要


任何帮助都将不胜感激。

您应该能够通过使用
ObjectDataProvider
来执行该方法,然后将附加属性绑定到提供程序的返回值

首先,您需要将提供程序配置为资源:

<Window.Resources>
  <ObjectDataProvider x:Key="readOnlyProvider" ...>
    <ObjectDataProvider.MethodParameters>
      ...
    </ObjectDataProvider.MethodParameters>
  </ObjectDataProvider>
</Window.Resources>
或者,当视图加载时,将提供程序的
ObjectInstance
设置为视图的
DataContext

public class MyWindow : Window
{
  public MyWindow()
  {
    InitializeComponent();

    var readOnlyProvider = this.Resources["readOnlyProvider"] as ObjectDataProvider;
    readOnlyProvider.ObjectInstance = this.DataContext;
  }
}

没有办法绑定到XAML中的方法,我所知道的唯一解决方法是使用
ObjectDataProvider

我建议使用转换器。下面是一个例子。假设您有一个简单的ViewModel类:

类视图模型
{
公共字符串读取
{get;set;}
公共字符串读写
{get;set;}
公共bool IsPropertyReadOnly(字符串propertyName)
{
返回propertyName!=“读写”;
}
}
要解决您的问题,您需要编写一个转换器,例如:

公共类转换器:IValueConverter
{
公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性)
{
var vm=作为ViewModel的值;
var functionName=(字符串)参数;
var result=vm.IsPropertyReadOnly(函数名);
返回结果;
}
公共对象转换回(对象值、类型targetType、对象参数、CultureInfo区域性)
{
抛出新的NotSupportedException(“永远不应该调用此方法”);
}
}
仅此而已;现在您可以在XAML中使用此转换器,如:

<Window.Resources>
    <temp:Converter x:Key="ReadOnlyMethodConverter"/>
</Window.Resources>
<StackPanel>
    <TextBox Text="{Binding Read, Mode=TwoWay}" 
             IsReadOnly="{Binding Path=.,
        Converter={StaticResource ReadOnlyMethodConverter}, ConverterParameter=Read}"
    />
    <TextBox Text="{Binding ReadWrite, Mode=TwoWay}" 
             IsReadOnly="{Binding Path=.,
        Converter={StaticResource ReadOnlyMethodConverter}, ConverterParameter=ReadWrite}"
    />
</StackPanel>
此外,要使用现有实例,我必须在代码隐藏中进行赋值。再说一次,不是我想做的

但事实并非如此,你的选择将是有限的


索引器呢

private readonly Dictionary_PropertyReadOnlyDictionary=new Dictionary();
公共字典PropertyReadOnlyDictionary{get{return{U PropertyReadOnlyDictionary;}}
公共类属性只读Resolver
{
public bool this[string propertyName]
{
得到
{
返回IsPropertyReadOnly(propertyName);
}
}
公共bool IsPropertyReadOnly(字符串propertyName)
{
//...
}
}


但是,我不希望
ObjectDataProvider
创建新对象。如果我能设置提供者的对象就好了。有趣的是,我们一开始确实使用了索引器。我决定不使用它,因为我们需要使用
IDataErrorInfo
。我喜欢第一个带字典的索引器,因为它更适合我们的实现。我们使用了PropertyReadOnlyDictionary实现,它与我们的设计完美集成。非常感谢。@AMissico:很高兴听到这一点:)尽管我在另一个答案中使用了H.B.的建议,但我还是接受了这个答案并投票表决,因为我认为它完全回答了关于绑定到视图模型上带有参数的方法的问题。我认为前面的评论中有太多的答案:O) 以下可能是您问题的答案(使用转换器的最后一个答案):
public class MyWindow : Window
{
  public MyWindow()
  {
    InitializeComponent();

    var readOnlyProvider = this.Resources["readOnlyProvider"] as ObjectDataProvider;
    readOnlyProvider.ObjectInstance = this.DataContext;
  }
}
<Window.Resources>
    <temp:Converter x:Key="ReadOnlyMethodConverter"/>
</Window.Resources>
<StackPanel>
    <TextBox Text="{Binding Read, Mode=TwoWay}" 
             IsReadOnly="{Binding Path=.,
        Converter={StaticResource ReadOnlyMethodConverter}, ConverterParameter=Read}"
    />
    <TextBox Text="{Binding ReadWrite, Mode=TwoWay}" 
             IsReadOnly="{Binding Path=.,
        Converter={StaticResource ReadOnlyMethodConverter}, ConverterParameter=ReadWrite}"
    />
</StackPanel>
<TextBox Text="{Binding Address, Mode=TwoWay}"
        IsReadOnly="{Binding PropertyReadOnlyDictionary[Address]}" />