在 XAML 绑定表达式中使用变量 [英] Using a variable in XAML binding expression
问题描述
我正在构建一个可以编辑 POCO 的控件.POCO 中需要编辑的字段有一个描述符集合,我将 ListBox
的 ItemsSource
绑定到该集合.除其他外,描述符使我能够选择合适的 DataTemplate
和 POCO 中此 ListBox
项应编辑的变量名称.
I'm building a control that can edit POCOs. There is a descriptor collection for the fields within the POCO that need to be edited and I'm binding a ListBox
's ItemsSource
to this collection. Amongst other things, the descriptor gives me the ability to select a suitable DataTemplate
and the variable name in the POCO that this ListBox
item should edit.
我的列表框是这样构建的:
My ListBox is built like this:
<ListBox ItemsSource="{Binding ColumnCollection, ElementName=root}">
<ListBox.Resources>
<DataTemplate x:Key="TextTemplate">
<StackPanel>
<TextBlock Text="{Binding DisplayName}" />
<!-- !!! Question about following line !!! -->
<TextBox Text="{Binding ElementName=vm.CurentEditing, Path=PathName}" />
</StackPanel>
</DataTemplate>
<!-- Details omitted for brevity -->
<DataTemplate x:Key="PickListTemplate" />
<DataTemplate x:Key="BooleanTemplate" />
</ListBox.Resources>
<ListBox.ItemTemplateSelector>
<local:DataTypeSelector
TextTemplate="{StaticResource TextTemplate}"
PickListTemplate="{StaticResource PickListTemplate}"
BooleanTemplate="{StaticResource BooleanTemplate}"
/>
</ListBox.ItemTemplateSelector>
</ListBox>
这是我遇到问题的TextTemplate"中的 TextBox
绑定表达式.问题是PathName"不应该被视为文字字符串,而是 ColumnDescription
类中的字符串属性的名称(ColumnCollection
的集合类型用于ListBox.ItemsSource
),它给出了我想要绑定的 POCO 属性的名称(POCO 是vm.CurrentEditing").
It is the TextBox
binding expression in the "TextTemplate" that I am having problems with. The problem is that "PathName" should not be taken as a literal string, but is the name of a string property in the ColumnDescription
class (the collection type of ColumnCollection
used for ListBox.ItemsSource
), which gives the name of the POCO property I want to bind to (the POCO is "vm.CurrentEditing").
是否有某种方法可以将 XAML 中的属性值用作绑定表达式的输入,还是我必须求助于代码?
Is there some way to use the value of a property in XAML as input to a binding expression, or will I have to resort to code behind?
(顺便说一句,将 ElementName
指定为xy",正如我在上面所做的那样似乎也是无效的.我认为y"部分应该在 Path
中,但是目前我的财产名称已占用...!)
(Incidentally, specifying the ElementName
as "x.y" as I have done above also seems to be invalid. I assume the "y" part should be in Path
but that's currently taken up with my property name...!)
推荐答案
所以您想将 TextBox.Text
绑定到对象 Y 的属性 X,其中 X 和 Y 都在运行时更改.
So you want to bind TextBox.Text
to Property X of Object Y, where X and Y both change at runtime.
听起来你想要做的事情类似于 ListBox.DisplayMemberPath
:你可以将 string
或 PropertyPath
属性绑定到 DisplayMemberPath
它将起作用.我做这样的事情的方法是拥有一个 String
或 PropertyPath
类型的依赖属性,并以编程方式创建一个从它到任何属性的绑定.
It sounds like what you want to do is something analogous to ListBox.DisplayMemberPath
: You can bind a string
or PropertyPath
property to DisplayMemberPath
and it'll work. The way I've done stuff like that is to have a dependency property of type String
or PropertyPath
, and programatically create a binding from that to whatever property.
因此,我编写了一个附加属性来创建绑定.
So, I wrote an attached property which creates a binding.
public class POCOWrangler
{
#region POCOWrangler.BindPropertyToText Attached Property
public static String GetBindPropertyToText(TextBox obj)
{
return (String)obj.GetValue(BindPropertyToTextProperty);
}
public static void SetBindPropertyToText(TextBox obj, PropertyPath value)
{
obj.SetValue(BindPropertyToTextProperty, value);
}
public static readonly DependencyProperty BindPropertyToTextProperty =
DependencyProperty.RegisterAttached("BindPropertyToText", typeof(String), typeof(POCOWrangler),
new PropertyMetadata(null, BindPropertyToText_PropertyChanged));
private static void BindPropertyToText_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is String && d is TextBox)
{
var tb = d as TextBox;
var binding = new Binding((String)e.NewValue);
// The POCO object we're editing must be the DataContext of the TextBox,
// which is what you've got already -- but don't set Source explicitly
// here. Leave it alone and Binding.Source will be updated as
// TextBox.DataContext changes. If you set it explicitly here, it's
// carved in stone. That's especially a problem if this attached
// property gets initialized before DataContext.
//binding.Source = tb.DataContext;
binding.Mode = BindingMode.TwoWay;
BindingOperations.SetBinding(tb, TextBox.TextProperty, binding);
}
}
#endregion POCOWrangler.BindPropertyToText Attached Property
}
我写了一个简单的例子:有一个名为 Foo
的小类,它有一个 Name
属性,以及一个具有两个属性的视图模型,Foo Foo
和 String DisplayPathName
.有用!当然,这取决于属性碰巧是什么类型的默认 TextBox
编辑行为.我认为这会给您带来与在 XAML 中显式绑定的结果相同的结果,但它不一定总是您想要的.但是你可以很容易地在DataTemplate
中添加一些触发器来切换不同的编辑器,或者编写一个DataTemplateSelector
.
And I wrote a quick example thing: There's a little class named Foo
that has a Name
property, and a viewmodel with two properties, Foo Foo
and String DisplayPathName
. It works! Of course, this depends on default TextBox
editing behavior for whatever type the property happens to be. I think that will get you the same results as if you'd bound explicitly in XAML, but it sitll won't always necessarily be just what you want. But you could very easily go a little nuts and add some triggers in the DataTemplate
to swap in different editors, or write a DataTemplateSelector
.
我将 ViewModel.Foo
塞进了 ContentControl
中,只是为了让 DataTemplate
生效,这样 TextBox
以与您相同的方式获取他的 DataContext
.
I stuffed ViewModel.Foo
in a ContentControl
just to get a DataTemplate
into the act, so that the TextBox
gets his DataContext
in the same manner as yours.
另请注意,我从 DataContext
对象之外的某个相对源获得了 DisplayPathName
-- 它不是 DisplayPathName
的成员code>Foo,当然是viewmodel的成员.
Note also that I'm getting DisplayPathName
by a relative source from something outside the DataContext
object -- it's not a member of Foo
, of course, it's a member of the viewmodel.
C#
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel {
DisplayPathName = "Name",
Foo = new Foo { Name = "Aloysius" }
};
}
XAML
<ContentControl
Content="{Binding Foo}"
>
<ContentControl.ContentTemplate>
<DataTemplate>
<TextBox
local:POCOWrangler.BindPropertyToText="{Binding
DataContext.DisplayPathName,
RelativeSource={RelativeSource AncestorType=ContentControl}}"
/>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
那很有趣.
这篇关于在 XAML 绑定表达式中使用变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!