在XAML绑定表达式中使用变量

时间:2016-06-28 17:00:37

标签: wpf xaml

我正在构建一个可以编辑POCO的控件。 POCO中的字段有一个描述符集合,需要进行编辑,我将ListBox ItemsSource绑定到此集合。除此之外,描述符使我能够在POCO中选择合适的DataTemplate和变量名称,该ListBox项应该编辑。

我的ListBox是这样构建的:

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

它是&#34; TextTemplate&#34;中的TextBox绑定表达式。我遇到了问题。问题是&#34; PathName&#34;不应该被视为文字字符串,而是ColumnDescription类中的字符串属性的名称(用于ColumnCollection的集合类型ListBox.ItemsSource),它给出了我要绑定的POCO属性(POCO是&#34; vm.CurrentEditing&#34;)。

有没有办法在XAML中使用属性的值作为绑定表达式的输入,还是我必须求助于代码?

(顺便说一下,将ElementName指定为&#34; x.y&#34;正如我上面所做的那样似乎也是无效的。我认为&#34; y&#34;部分应该在Path,但目前我的财产名称已被占用......!)

1 个答案:

答案 0 :(得分:1)

因此,您希望将TextBox.Text绑定到对象Y的属性X,其中X和Y都在运行时更改。

听起来你想做的事情类似于ListBox.DisplayMemberPath:你可以将stringPropertyPath属性绑定到DisplayMemberPath并且它可以正常工作。我这样做的方式是拥有类型为StringPropertyPath的依赖项属性,并以编程方式创建从该属性到任何属性的绑定。

所以,我写了一个附加属性,它创建了一个绑定。

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和{{1}的视图模型}}。有用!当然,这取决于属性恰好是什么类型的默认String DisplayPathName编辑行为。我认为这会得到与你在XAML中明确约束的结果相同的结果,但它并不总是一定只是你想要的。但你可以很容易地在TextBox中添加一些触发器来交换不同的编辑器,或者写一个DataTemplate

我在DataTemplateSelector填充ViewModel.Foo只是为了获得ContentControl行为,以便DataTemplate以与TextBox相同的方式获得DataContext你的。

另请注意,我从DisplayPathName对象之外的某个地方获取相对来源DataContext - 它不是{的成员{1}},当然,它是viewmodel的成员。

C#

Foo

XAML

public MainWindow()
{
    InitializeComponent();

    DataContext = new ViewModel { 
            DisplayPathName = "Name",
            Foo = new Foo { Name = "Aloysius" }
        };
}

这很有趣。