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

时间:2012-02-04 00:01:54

标签: wpf xaml data-binding methods markup-extensions

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

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

这就是我设想的语法:

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

DataContext包含视图模型,所以基本上我需要将IsReadOnly绑定到调用的结果((Class)this.DataContext).IsPropertyReadOnly("Address")

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

根据我的研究,似乎继承自BindingMarkupExtension的解决方案更适合我的需求。

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:4)

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

class ViewModel
{
    public string Read
    { get; set; }

    public string ReadWrite
    { get; set; }

    public bool IsPropertyReadOnly(string propertyName)
    {
        return propertyName != "ReadWrite";
    }
}

要解决您的问题,您需要编写转换器,例如:

public class Converter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var vm = value as ViewModel;
        var functionName = (string)parameter;

        var result = vm.IsPropertyReadOnly(functionName);
        return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException("This method should never be called");
    }
}

就是这样;现在您可以在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>

在代码隐藏中,我们只创建ViewModel并将其设置为DataContext:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }
}

答案 1 :(得分:4)

  

此外,要使用现有实例,我必须在代码隐藏中进行赋值。再一次,不是我想做的事。

事实并非如此,但您的选择将受到限制。


索引器怎么样?

private readonly Dictionary<string, bool> _PropertyReadOnlyDictionary = new Dictionary<string, bool>();
public Dictionary<string, bool> PropertyReadOnlyDictionary { get { return _PropertyReadOnlyDictionary; } }
<TextBox Text="{Binding Address, Mode=TwoWay}"
        IsReadOnly="{Binding PropertyReadOnlyDictionary[Address]}" />

您当然可以将您的方法包装在一个新类中,如果您不想使用字典,也可以通过索引器进行访问。

private readonly PropertyIsReadOnlyResolver _PropertyIsReadOnlyResolver = new PropertyIsReadOnlyResolver();
public PropertyIsReadOnlyResolver PropertyIsReadOnlyResolver { get { return _PropertyIsReadOnlyResolver; } }
public class PropertyIsReadOnlyResolver
{
    public bool this[string propertyName]
    {
        get
        {
            return IsPropertyReadOnly(propertyName);
        }
    }

    public bool IsPropertyReadOnly(string propertyName)
    {
        //...
    }
}
<TextBox Text="{Binding Address, Mode=TwoWay}"
        IsReadOnly="{Binding PropertyIsReadOnlyResolver[Address]}" />

答案 2 :(得分:0)

您应该可以使用ObjectDataProvider执行该方法,然后将附加属性绑定到提供程序的返回值。

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

<Window.Resources>
  <ObjectDataProvider x:Key="readOnlyProvider" ...>
    <ObjectDataProvider.MethodParameters>
      ...
    </ObjectDataProvider.MethodParameters>
  </ObjectDataProvider>
</Window.Resources>

然后使用提供者作为附加属性绑定的来源:

<TextBox Text="{Binding PoolNum, Mode=OneWay}" Windows:AttachedProperties.IsReadOnlyOn="{Binding Source={StaticResource readOnlyProvider}}" />

此过程中棘手的部分是将值“传递”到ObjectDataProviders.MethodParameters。这可以在XAML中完成,有几个资源可以告诉你它是如何完成的;这是一个入门:http://weblogs.asp.net/psheriff/archive/2010/02/23/bind-objectdataprovider-method-parameters-in-wpf.aspx

<强>更新

根据您的评论,ObjectDataProvider可以通过两种方式在您的视图DataContext上执行该方法,而无需创建新对象。

首先,将您的视图模型方法设为静态并使用ObjectType属性:

<ObjectDataProvider x:Key="readOnlyProvider"
  ObjectType="{x:local MyDataContext}"
  MethodName="IsPropertyReadOnly">
  ...
</ObjectDataProvider>

或者,在视图加载时,将提供程序的ObjectInstance设置为视图的DataContext

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

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

无法绑定XAML中的方法,我知道的唯一解决方法是使用ObjectDataProvider