【问题标题】:How do I data bind the result of a view-model method to a TextBox property?如何将视图模型方法的结果数据绑定到 TextBox 属性?
【发布时间】:2012-02-26 13:41:29
【问题描述】:

在我的视图模型和模型中,我有一个签名为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 继承的解决方案似乎更适合我的需求。

任何帮助将不胜感激。

【问题讨论】:

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


【解决方案1】:

我建议使用转换器。这是示例。假设你有一个简单的 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();
    }
}

【讨论】:

  • 尽管我使用了 H.B. 的建议。在另一个答案中,我接受并投票了这个答案,因为我认为它完全回答了绑定到具有视图模型参数的方法的问题。
  • 我觉得上一条评论的答案太多了。 :O)
【解决方案2】:

此外,要使用现有实例,我必须在代码隐藏中进行分配。再说一遍,这不是我想做的。

这不是真的,但是您的选择将受到限制。


索引器怎么样?

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]}" />

【讨论】:

  • 有趣的是,我们一开始确实使用了索引器。我决定反对它,因为我们需要使用IDataErrorInfo。我喜欢第一个带有字典的索引器,因为它更适合我们的实现。
  • 我们使用了 PropertyReadOnlyDictionary 实现,它与我们的设计完美集成。非常感谢。
  • @AMissico:很高兴听到这个消息:)
【解决方案3】:

您应该能够通过使用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

【讨论】:

  • 但是,我不希望 ObjectDataProvider 创建一个新对象。如果我能设置提供者的对象就好了。
猜你喜欢
  • 2016-04-25
  • 1970-01-01
  • 2010-09-27
  • 2010-12-02
  • 2023-03-20
  • 1970-01-01
  • 2021-04-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多