[英]Add different controls in ItemsControl
我需要根據特定條件在ItemsControl中添加不同的控件(TextBox / CheckBox / ComboBox等)。 ItemsControl中的每個項目都是一個“名稱/值”對。 名稱始終由TextBlock表示,但Value可以是任何UI控件。 我正在使用水平對齊的StackPanel來表示每個項目。 StackPanel中的第一個控件仍為TextBlock,但第二個控件取決於在運行時在ViewModel中設置的“ ItemDataType”屬性。
我遇到的問題是我無法使用帶有ItemDataType屬性的樣式觸發器在StackPanel的第二個元素中分配不同的控件。
代碼段:
<UserControl.Resources>
<DataTemplate x:Key="TextBoxTemplate">
<TextBox Text="{Binding Path=DataValue}"/>
</DataTemplate>
<DataTemplate x:Key="ComboBoxTemplate">
<ComboBox ItemsSource="{Binding Path=SelectionList}" SelectedValue="{Binding Path=DataValue,Mode=TwoWay}"/>
</DataTemplate>
<DataTemplate x:Key="CheckBoxTemplate">
<CheckBox IsChecked="{Binding Path=DataValue,Mode=TwoWay}" />
</DataTemplate>
<DataTemplate x:Key="ButtonTemplate">
<Button Content="{Binding Path=DataValue}"/>
</DataTemplate>
<DataTemplate x:Key="dynamicTemplate">
<StackPanel Orientation="Horizontal" Tag="{Binding ItemDataType}">
<TextBlock Text="{Binding Path=DataName,Mode=TwoWay}"/>
<ContentControl>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding ItemDataType}" Value="TextBox">
<Setter Property="Template" Value="{StaticResource TextBoxTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<!-- CONTROL LAYOUT -->
<ItemsControl ItemsSource="{Binding Path=DataList,Mode=TwoWay}" ItemTemplate="{StaticResource dynamicTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
我得到的錯誤是DataTemplate對ContentControl.Template屬性無效。 我知道我在做什么是錯誤的,但是我需要幫助以正確的方式做。
謝謝,
RDV
答案( 或答案)是寫一個DataTemplateSelector
返回基於一些任意參數正確的模板。 類似於以下內容(請排除所有空檢查樣板噪聲;將其直接復制出生產代碼)。
/// <summary>
/// Selects template based on the value of a named property of the data item.
/// Property name is specified by ResourceKeyPropertyName.
/// </summary>
public class PropertyValueTemplateSelector : DataTemplateSelector
{
/// <summary>
/// Gets or sets a path to a value on the source object to serve as a resource key for
/// the DataTemplate used to display the source object.
/// </summary>
public string ResourceKeyPropertyName { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var context = container as FrameworkElement;
DataTemplate template = null;
if (null == container)
{
throw new NullReferenceException("container");
}
else if (null == context)
{
throw new Exception("container must be FramekworkElement");
}
else if (String.IsNullOrEmpty(ResourceKeyPropertyName))
{
throw new NullReferenceException("ResourceKeyPropertyName");
}
else if (null == item)
{
return null;
}
var prop = item.GetType().GetProperty(ResourceKeyPropertyName);
if (null == prop)
{
throw new Exception("Undefined property " + ResourceKeyPropertyName);
}
var resourceKey = prop.GetValue(item, null);
if (null != resourceKey)
{
try
{
template = context.FindResource(resourceKey) as DataTemplate;
}
catch (Exception ex)
{
Ability.CAPS.WPF.Utilities.ErrorHandler.HandleException(ex, Ability.Logging.AbilityExceptionPolicy.GeneralExceptionPolicy);
template = null;
}
}
return template ?? base.SelectTemplate(item, container);
}
}
在XAML中像這樣使用:
<ItemsControl
>
<ItemsControl.ItemTemplateSelector>
<!-- Tell it use the value of the "DataName" property as the
resource key for the template it uses.
-->
<local:PropertyValueTemplateSelector
ResourceKeyPropertyName="DataName" />
</ItemsControl.ItemTemplateSelector>
<!-- etc.
etc.
etc. -->
</ItemsControl>
如果某個項目的DataName
屬性是“富”,這將看在當地背景的DataTemplate
,其資源的關鍵是“富”,並使用-這樣命名DataTemplates
因此,去城鎮。 沒有更簡單或更通用的方法可以做到這一點。 順便說一下,在我們的代碼中,此刻僅在一個地方使用(我上個月才寫過),並且它對資源鍵而不是字符串使用枚舉值。 任何對象都可以。 資源密鑰不必是字符串。
或者,您可能需要查找或將DataName
值轉換為另一組鍵的工具。 您的電話,如果更適合您的需求。
另一種選擇是使一個項目模板帶有一組觸發器,該觸發器根據DataName
的值在內部 ContentControl上設置模板。 這是做類似這樣的回答的 。
我想要一個XAML解決方案-花了我一段時間:-)。 下面是工作代碼:
<Style x:Key="nvpTextBlockStyle" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Width" Value="{Binding Path=LabelWidthStr, FallbackValue=50}"/>
<Setter Property="Margin" Value="0,5,0,5"/>
<Setter Property="Text" Value="{Binding Path=NameData,Mode=TwoWay}"/>
<Setter Property="FontSize" Value="16"/>
</Style>
<DataTemplate x:Key="textBoxTemplate">
<TextBox Margin="1,1" Text="{Binding Path=ValueData,UpdateSourceTrigger=PropertyChanged,
ValidatesOnExceptions=True,NotifyOnValidationError=True,ValidatesOnDataErrors=True}"/>
</DataTemplate>
<DataTemplate x:Key="comboBoxTemplate">
<ComboBox HorizontalAlignment="Left" ItemsSource="{Binding Path=SelectionList}"
SelectedValue="{Binding Path=ValueData,Mode=TwoWay}"
IsEnabled="{Binding IsDataItemEnabled}"/>
</DataTemplate>
<DataTemplate x:Key="checkBoxTemplate">
<CheckBox HorizontalAlignment="Left" VerticalAlignment="Center"
IsChecked="{Binding Path=ValueData,Mode=TwoWay}"/>
</DataTemplate>
<DataTemplate x:Key="buttonTemplate">
<Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.AddCommand}"
CommandParameter="{Binding}" Width="30" Height="25">
<TextBlock Text="🔑" FontFamily="Segoe UI Symbol" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Gray" />
</Button>
</DataTemplate>
<DataTemplate x:Key="dynamicTemplate">
<StackPanel Orientation="Horizontal" Margin ="5">
<TextBlock Style="{StaticResource nvpTextBlockStyle}"/>
<ContentPresenter Content="{Binding}"
Tag="{Binding Path=CustomDataType, FallbackValue={x:Static local:CustomViewModel.TEXTBOX_TEMPLATE}}">
<ContentPresenter.Resources>
<Style TargetType="{x:Type ContentPresenter}">
<Style.Triggers>
<Trigger Property="Tag" Value="{x:Static local:CustomViewModel.TEXTBOX_TEMPLATE}">
<Setter Property="ContentTemplate" Value="{StaticResource textBoxTemplate}"/>
</Trigger>
<Trigger Property="Tag" Value="{x:Static local:CustomViewModel.COMBOBOX_TEMPLATE}">
<Setter Property="ContentTemplate" Value="{StaticResource comboBoxTemplate}"/>
</Trigger>
<Trigger Property="Tag" Value="{x:Static local:CustomViewModel.CHECKBOX_TEMPLATE}">
<Setter Property="ContentTemplate" Value="{StaticResource checkBoxTemplate}"/>
</Trigger>
<Trigger Property="Tag" Value="{x:Static local:CustomViewModel.BUTTON_TEMPLATE}">
<Setter Property="ContentTemplate" Value="{StaticResource buttonTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</StackPanel>
</DataTemplate>
<Grid>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Path=CustomDataList,Mode=TwoWay}"
ItemTemplate="{StaticResource dynamicTemplate}";
KeyboardNavigation.IsTabStop="False">
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
謝謝,
RDV
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.