2017-03-14 126 views
-2

我剛剛瞭解如何創建自定義UserControls,我現在正在學習DataTemplates,但仍然瞭解屬性,因此我可以想象控件屬性的實現是錯誤的。基於自定義用戶控件中的Enum屬性的WPF自定義DataTemplateSelector

我已經創建了一個名爲ExtendedListBox的UserControl,它可以用複選框或正常列表框顯示它的項目。以下是ExtendedListBox的實現DisplayAs屬性用於選擇要使用哪個DataTemplate。

我已經在StackOverflow上看到了很多與DataTemplateSelectors相關的問題,現在我想問一下這個實現是否應該由ContentControl完成? (參見:Bind a property to DataTemplateSelector

public partial class ExtendedListBox : UserControl 
{ 
    public ExtendedListBoxDisplay DisplayAs { get; set; } 

    public ExtendedListBox() 
    { 
     InitializeComponent(); 
    } 
} 

下面是用戶控件的DataTemplates都在用戶控件資源爲CheckedListBoxTemplate和ListBoxTemplate

<UserControl x:Class="UserControlTest.Configuration.Controls.ExtendedListBox" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:enums="clr-UserControlTest.Configuration.Enums" 
      xmlns:local="clr-UserControlTest.Configuration.Controls" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:templateSelectors="clr-namespace:UserControlTest.Configuration.Controls.TemplateSelectors" 
      x:Name="UcExtendedListBox" 
      d:DesignHeight="84" 
      d:DesignWidth="100" 
      SizeChanged="ResizeControl" 
      mc:Ignorable="d"> 
    <UserControl.Resources> 
     <ResourceDictionary> 
      <DataTemplate x:Key="CheckedListBoxTemplate" DataType="enums:ExtendedListBoxDisplay"> 
       <CheckBox IsChecked="{Binding IsChecked}"> 
        <TextBlock Text="{Binding}" TextWrapping="Wrap" /> 
       </CheckBox> 
      </DataTemplate> 
      <DataTemplate x:Key="ListBoxTemplate" DataType="enums:ExtendedListBoxDisplay"> 
       <TextBlock Text="{Binding}" TextWrapping="Wrap" /> 
      </DataTemplate> 
     </ResourceDictionary> 
    </UserControl.Resources> 
    <ListBox x:Name="LstItems" 
      Grid.Row="2" 
      Width="{Binding ActualWidth, 
          ElementName=UcExtendedListBox}" 
      HorizontalAlignment="Center" 
      VerticalAlignment="Center" 
      HorizontalContentAlignment="Center" 
      ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
      ScrollViewer.VerticalScrollBarVisibility="Visible" 
      SelectionChanged="RaiseSelectionChanged"> 
        <ItemsControl> 
      <ItemsControl.ItemTemplateSelector> 
       <templateSelectors:ExtendedListBoxDataTemplateSelector 
         CheckedListBoxTemplate="{StaticResource CheckedListBoxTemplate}" 
         ListBoxTemplate="{StaticResource ListBoxTemplate}" /> 
      </ItemsControl.ItemTemplateSelector> 
     </ItemsControl> 
    </ListBox> 
</UserControl> 

這是DataTemplateSelector它的實現是相當簡單的XAML。

public class ExtendedListBoxDataTemplateSelector : DataTemplateSelector 
{ 
    public DataTemplate CheckedListBoxTemplate { get; set; } 

    public DataTemplate ListBoxTemplate { get; set; } 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     if (item == null) 
     { 
      return base.SelectTemplate(item, container); 
     } 

     var data = (ExtendedListBoxDisplay)item; 

     switch (data) 
     { 
      case ExtendedListBoxDisplay.CheckedListBox: 
       return CheckedListBoxTemplate; 
      case ExtendedListBoxDisplay.ListBox: 
       return ListBoxTemplate; 
      default: 
       return base.SelectTemplate(item, container); 

     } 
    } 
} 

所以我去跑這個,它不工作,我猜是因爲我沒有綁定項目和屬性來尋找?作爲DataTemplateSelectors的第一次使用者,有沒有人能夠以正確的方向引導我?

非常感謝。

+0

你綁定了什麼項目到ListBox?你在用什麼「DisplayAs」? –

+0

好問題,我還沒有使用綁定,所以我只是用隨機的對象列表來填充這些對象 - 試圖保持它的通用性,但是看起來並不像是可以做到的,DisplayAs應該是用於設置列表框中要使用哪個DataTemplate – Andy

+0

以及DataTemplates是基於綁定的項目的類型工作的,因此DataTemplate的目標類型需要與綁定到ListBox的項目的類型相匹配。在這種情況下,使用ControlTemplate可能會更好,因爲您似乎不太關心綁定到ListBox的數據類型。 –

回答

0

應設置或ListBoxItemsSource屬性綁定到一個IEnumerable<ExtendedListBoxDisplay>(或IEnumerable<YourDataObject>實際上):

public partial class ExtendedListBox : UserControl 
{ 
    public ExtendedListBoxDisplay DisplayAs { get; set; } 

    public ExtendedListBox() 
    { 
     InitializeComponent(); 
     LstItems.ItemsSource = new List<ExtendedListBoxDisplay>() { new ExtendedListBoxDisplay() }; 
    } 
} 

ExtendedListBoxDataTemplateSelector類的SelectTemplate方法將每件ItemsSource集合中被調用一次,您返回的DataTemplate將應用於此項目。

傳遞給該方法的object參數是對ItemsSource中相應項目的引用。

請注意,如果ExtendedListBoxDisplay實際上是一個枚舉,那麼您應該修改SelectTemplate方法並將ItemsSource設置爲另一種類型。

0

基本上你必須將枚舉值設置爲dataTemplate。希望這個鏈接有幫助,它提供了一些見解如何做到這一點。 DataTemplate in case of Enum 希望這會有所幫助。

0

首先,當您指定DataTypeDataTemplate時,您說模板只應用於該類型的項目(或從該類型派生)。 因此,您需要做的第一件事是從兩個模板中刪除DataType="enums:ExtendedListBoxDisplay"

接下來,您需要修改模板選擇器,以使用綁定的DependancyObject而不是數據本身,因爲您並不在乎數據類型是什麼。

E.G:

public class ExtendedListBoxDataTemplateSelector : DataTemplateSelector 
{ 
    public DataTemplate CheckedListBoxTemplate { get; set; } 

    public DataTemplate ListBoxTemplate { get; set; } 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     if (container == null || !(container is ExtendedListBox)) 
     { 
      return base.SelectTemplate(item, container); 
     } 

     var listBox = (ExtendedListBox)container; 

     switch (listBox.DisplayAs) 
     { 
      case ExtendedListBoxDisplay.CheckedListBox: 
       return CheckedListBoxTemplate; 
      case ExtendedListBoxDisplay.ListBox: 
       return ListBoxTemplate; 
      default: 
       return base.SelectTemplate(item, container); 

     } 
    } 
} 

所以現在,而不是期待的項目是一個ExtendedListBoxDisplay枚舉,我們現在期待的容器是一個ExtendedListBox。然後我們檢查ExtendedListBox的DisplayAs屬性,並使用它來確定顯示哪個模板。