2010-05-26 50 views
5

我有一個屬性是數據庫數據類型(char,datetime,int,float等等),我想改變用於輸入值的控件的選定類型。所以對於文本值我想要一個TextBox和日期值我想DatePicker動態顯示一個控件取決於綁定屬性使用WPF

我想過這樣做的一種方法是讓我的表單上的每個控件都有一個,並使用適當的IValueConverter實現來設置Visibility。我知道這會起作用,但它會產生很多代碼,並且感覺不太好。

我認爲的另一種方式是使用ContentPresenter並將它的內容設置爲StyleDataTriggers但我無法使其工作。

<Style x:Key="TypedValueHelper" TargetType="{x:Type ContentPresenter}"> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding Path=DataType}" Value="Char"> 
       <Setter Property="Content" Value="???"/> 
      </DataTrigger> 
      <DataTrigger Binding="{Binding Path=DataType}" Value="Date"> 
       <Setter Property="Content" Value="???"/> 
      </DataTrigger> 
      <DataTrigger Binding="{Binding Path=DataType}" Value="Integer"> 
       <Setter Property="Content" Value="???"/> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 

如果有人可以填寫我的「???」或者提供更好的解決方案,請做。

回答

10

您可以將樣式與setter和datatemplates結合使用。您基本上已經在代碼中開始了它,但我不認爲ContentPresenter是風格的正確控件,因爲它沒有模板。

可能是這樣的:

<Style x:Key="TypedValueHelper" TargetType="{x:Type ContentControl}"> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding Path=DataType}" Value="Char"> 
       <Setter Property="ContentTemplate"> 
        <Setter.Value> 
         <DataTemplate> 
          <TextBox Text="{Binding Path=.}" /> 
         </DataTemplate> 
        </Setter.Value> 
       </Setter> 
      </DataTrigger> 
      <DataTrigger Binding="{Binding Path=DataType}" Value="Integer"> 
       <Setter Property="ContentTemplate"> 
        <Setter.Value> 
         <DataTemplate> 
          <Slider Maximum="100" Minimum="0" Value="{Binding Path=.}" 
              Orientation="Horizontal" /> 
         </DataTemplate> 
        </Setter.Value> 
       </Setter> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 

...

<ContentControl Content="{Binding MyValue}" 
         Style="{StaticResource TypedValueHelper}"> 
+0

你可以在現階段分享你的代碼嗎? – ThomasAndersson 2010-05-26 11:39:28

+0

我不確定我可以分享我的代碼,因爲有很多依賴關係。事實上,我的實際問題比我放慢了一點。我敢肯定你的解決方案將爲我工作我剛剛遇到了一個問題,我試圖將ContentControl的內容設置爲{Binding}而不是{Binding MyValue},這意味着WPF會爲我的ViewModel加載視圖在內容控制中,遞歸地繼續前進... – 2010-05-26 11:54:52

+0

啊我明白了。你嘗試過{Binding Path =。}嗎? – ThomasAndersson 2010-05-26 12:11:54

0

我會研究DataTemplates。例如:

<DataTemplate DataType="{x:Type local:Input}"> 
      <local:InputControl DataContext="{Binding}" /> 
</DataTemplate> 

<DataTemplate DataType="{x:Type data:VideoData}"> 
       <local:VideoControl DataContext="{Binding}"></local:VideoControl> 
</DataTemplate> 
+0

我不確定這會對我有用,因爲我沒有使用實際的「類型」來選擇控件,我使用了作爲ViewModel屬性公開的枚舉值。 – 2010-05-26 10:04:52

5

雖然樣式的解決方案可能的工作,實現動態內容的行爲的正確方法是爲Sdry建議使用的DataTemplates 。但是,您將使用枚舉來確定要使用哪個DataTemplate;這基本上意味着您想要將單個類型映射到多個DataTemplates。此問題是由DataTemplateSelector類解決了,下面的描述是直接從MSDN:


「通常情況下,你創建一個DataTemplateSelector當你有相同類型的對象不止一個DataTemplate中,你要提供你的根據每個數據對象的屬性選擇一個DataTemplate來應用自己的邏輯。「


您的動態內容應該由ContentControl中主持這樣的:

<ContentControl Content="{Binding Path=ReferenceToYourViewModel}" ContentTemplateSelector="{DynamicResource MyTemplateSelector}"/> 

MyTemplateSelector的實現:

public class MyTemplateSelector: DataTemplateSelector 
{ 
    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     FrameworkElement elem = container as FrameworkElement; 
     if(elem == null) 
     { 
      return null; 
     } 
     if (item == null || !(item is YourViewModel)) 
     { 
      throw new ApplicationException(); 
     } 
     if ((item as YourViewModel).DataType == DataType.Char) 
     { 
      return elem.FindResource("CharDataTemplate") as DataTemplate; 
     } 
     if ((item as YourViewModel).DataType == DataType.Date) 
     { 
      return elem.FindResource("DateDataTemplate") as DataTemplate; 
     } 
     if ((item as YourViewModel).DataType == DataType.Integer) 
     { 
      return elem.FindResource("IntegerDataTemplate") as DataTemplate; 
     } 
     throw new ApplicationException(); 
    } 
} 

然後你所期望的,這裏的的DataTemplates挑來自:

<DataTemplate x:Key="CharDataTemplate" DataType="{x:Type YourViewModel}">Put Your Xaml Here</DataTemplate> 
    <DataTemplate x:Key="DateDataTemplate" DataType="{x:Type YourViewModel}">Put Your Xaml Here</DataTemplate> 
    <DataTemplate x:Key="IntegerDataTemplate" DataType="{x:Type YourViewModel}">Put Your Xaml Here</DataTemplate> 

這樣,將根據View Model的DataType屬性選擇適當的DataTemplate。在我看來,這比使用可視性或樣式更清潔。

相關問題