2016-06-28 71 views
1

我正在构建一个可以编辑POCO的控件。有一个POCO内的字段需要编辑的描述符集合,我将这个集合绑定到ListBoxItemsSource。除其他外,描述符使我能够选择合适的DataTemplate以及该项目应该编辑的POCO中的变量名称。在XAML绑定表达式中使用变量

我的列表框是建立这样的:

<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类(用于ListBox.ItemsSourceColumnCollection的集合类型)中的字符串属性的名称,该名称给出了我想要的POCO属性的名称绑定到(POCO是“vm.CurrentEditing”)。

是否有某种方法可以将XAML中的属性值用作绑定表达式的输入,还是必须使用后面的代码? (顺便说一下,如上所述,将ElementName指定为“xy”似乎也是无效的。我假设“y”部分应该在Path之内,但是目前我的属性名称已被占用......)

+1

'ElementName'只是名称,其他所有内容都在'Path'中,使用'.'来访问子属性。 –

+1

你想做类似于ListBox.DisplayMemberPath的事吗? –

+0

@ H.B。我认为一定是这种情况(并且可能在过去的某个时候知道)。感谢您的确认。 –

回答

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 FooString DisplayPathName一个视图模型。有用!当然,这取决于默认TextBox编辑行为的属性发生的任何类型。我认为这会得到与您在XAML中显式绑定相同的结果,但它不一定总是您想要的。但是你可以非常轻松地在DataTemplate中添加一些触发器来交换不同的编辑器,或者编写一个DataTemplateSelector

我在ContentControlViewModel.Foo只是为了获得一个DataTemplate插一脚,让TextBox得到他DataContext以同样的方式为你的。

还请注意,我得到DisplayPathName相对源从东西DataContext对象之外 - 它不是Foo一员,当然,它的视图模型中的一员。

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> 

这很有趣。

+0

超越!在这里,我问的是一个快速的XAML技巧是否可能,我得到一个彻底的,可重用的编码解决方案!非常感谢。 –

+0

@BobSammers你好。 –