在 XAML 绑定表达式中使用变量 [英] Using a variable in XAML binding expression

查看:23
本文介绍了在 XAML 绑定表达式中使用变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个可以编辑 POCO 的控件.POCO 中需要编辑的字段有一个描述符集合,我将 ListBoxItemsSource 绑定到该集合.除其他外,描述符使我能够选择合适的 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:你可以将 stringPropertyPath 属性绑定到 DisplayMemberPath 它将起作用.我做这样的事情的方法是拥有一个 StringPropertyPath 类型的依赖属性,并以编程方式创建一个从它到任何属性的绑定.

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 FooString 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆