6

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

任何帮助将不胜感激。

4

3 回答 3

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();
    }
}
于 2012-02-06T12:19:42.647 回答
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]}" />
于 2012-02-06T14:56:13.377 回答
0

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

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

<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.

于 2012-02-04T00:12:50.413 回答