2017-03-09 64 views
1

複選框中的綁定似乎有問題。它拋出一個XamlParseException,並說雙向綁定需要Path或XPath。這是用於評估的ContentPresenter。如何使CheckBox中的綁定在ContentPresenter中工作?

<ContentPresenter Content="{Binding PropertyValue}"> 
    <ContentPresenter.Resources> 
     <DataTemplate DataType="{x:Type System:String}"> 
      <TextBox Text="{Binding}" MinWidth="100" MaxWidth="300"/> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type System:Boolean}"> 
      <CheckBox IsChecked="{Binding}"/> 
     </DataTemplate> 
    </ContentPresenter.Resources> 
</ContentPresenter> 

我希望完成被給予其的PropertyValue是一個多態對象,和它的數據類型,相應的控制將在運行時被創建。例如,如果PropertyValue是一個布爾屬性,那麼該控件將是一個複選框。如果用戶切換複選框,則更改應反映在PropertyValue上。如果外部依賴項修改PropertyValue(例如INotifyPropertyChanged),則該複選框也必須反映該更改。因此,我需要一種方法來完成雙向綁定。

+0

你想讓它根據PropertyValue的類型選擇一個模板嗎?你可能需要一個TemplateSelector。 –

+0

是的。這就是我想要完成的 – Xegara

+0

任何機會,你的問題不是*「爲什麼不工作」*而是*「如何讓Y工作」*? – grek40

回答

0

錯誤是非常精確的...你不能雙向綁定你當前的DataContext但只有屬性上下文中。

<DataTemplate DataType="{x:Type ClassTypeContainingABoolean}"> 
    <CheckBox IsChecked="{Binding YourBooleanProperty}"/> 
</DataTemplate> 

<DataTemplate DataType="{x:Type System:Boolean}"> 
    <CheckBox IsChecked="{Binding Mode=OneWay}"/> 
</DataTemplate> 

取決於你真正想做什麼。

整個事情是從ContentPresenter獨立。


如果要檢查你的DataContext對象,決定模板之前,您可以使用TemplateSelector

public class MyTemplateSelector : DataTemplateSelector 
{ 
    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     var elem = container as FrameworkElement; 
     if (item == null || elem == null) 
     { 
      return null; 
     } 
     var t = item.GetType(); 
     var prop = t.GetProperty("PropertyValue"); 
     if (prop == null) 
     { 
      return null; 
     } 
     // select template by the type of the PropertyValue parameter 
     if (typeof(bool?).IsAssignableFrom(prop.PropertyType)) 
     { 
      return elem.FindResource("BooleanContextTemplate") as DataTemplate; 
     } 
     if (typeof(string).IsAssignableFrom(prop.PropertyType)) 
     { 
      return elem.FindResource("StringContextTemplate") as DataTemplate; 
     } 
     return base.SelectTemplate(item, container); 
    } 
} 

例如數據上下文初始化:

public class MyContextData<T> 
{ 
    public T PropertyValue { get; set; } 
} 

// initialize DataContext somewhere 
private void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    grid1.DataContext = new MyContextData<bool>() { PropertyValue = true }; 
    //grid1.DataContext = new MyContextData<string>() { PropertyValue = "ABC" }; 
} 

的XAML示例:

<Window.Resources> 
    <local:MyTemplateSelector x:Key="MyContextDataTemplateSelector"/> 

    <DataTemplate x:Key="StringContextTemplate"> 
     <TextBox Text="{Binding PropertyValue}" MinWidth="100" MaxWidth="300"/> 
    </DataTemplate> 

    <DataTemplate x:Key="BooleanContextTemplate"> 
     <CheckBox IsChecked="{Binding PropertyValue}"/> 
    </DataTemplate> 
</Window.Resources> 

<Grid x:Name="grid1"> 
    <ContentPresenter Content="{Binding}" ContentTemplateSelector="{StaticResource MyContextDataTemplateSelector}"/> 
</Grid> 

正如你所看到的,是由模板選擇通過FindResource("BooleanContextTemplate")引用的DataTemplate需要定義某處。此外,templateselector本身在資源中創建並傳遞給ContentPresenter.ContentTemplateSelector屬性。

請注意,ContentPresenter.Content綁定不再針對YourBooleanProperty,並且此屬性代替模板的一部分。因此,最終,您的數據需要以某種確定的方式進行打包,涉及相關的屬性名稱。

+0

爲什麼雙向綁定受到限制?我想完成的是:給定PropertyValue ,它是一個多態對象及其數據類型,相應的控件是在運行時創建的,例如,如果PropertyValue是布爾型的,我希望控件是一個複選框,當用戶切換複選框時,我希望更改爲反映在PropertyValue上,如果PropertyValue被其他方法修改了(例如通過INotifyPropertyChanged),那麼我希望它也被反射到複選框中,爲此,我不需要雙向數據綁定嗎? – Xegara

+0

@Xegara認爲datacontext就像一個函數參數。用'void MyContext(object value){var x = value;值= y; }'您可以讀取輸入,但如果您嘗試更改它,則只會更改本地值,而不會更改值。 – grek40

+0

這是否發生,因爲布爾是原始的,因此它是一個傳值變量? – Xegara

相關問題