簡體   English   中英

在ItemsControl中添加其他控件

[英]Add different controls in ItemsControl

我需要根據特定條件在ItemsControl中添加不同的控件(TextBox / CheckBox / ComboBox等)。 ItemsControl中的每個項目都是一個“名稱/值”對。 名稱始終由TextBlock表示,但Value可以是任何UI控件。 我正在使用水平對齊的StackPanel來表示每個項目。 StackPanel中的第一個控件仍為Te​​xtBlock,但第二個控件取決於在運行時在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="&#x1F511;" 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM