在我的视图模型和模型中,我有一个签名为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
时有很多文档,但对象数据提供程序会创建一个不是我想要的新对象实例。而且,要使用现有实例,我必须在代码隐藏中进行赋值。再一次,不是我想做的事。
根据我的研究,似乎继承自Binding
或MarkupExtension
的解决方案更适合我的需求。
非常感谢任何帮助。
答案 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
。