Значение ItemSource может оценивать, чтобы выбрать стиль между меткой или переключателями - PullRequest
0 голосов
/ 09 июля 2020

Я ищу пример wpf, когда Itemsource больше 1, тогда он может динамически создавать переключатель. Если это только одно значение в Itemsource, тогда оно должно быть меткой, а не переключателями. Нужно ли мне писать конвертер, который может передавать значение Itemsource и управлять стилем между меткой и переключателем. Если кто-нибудь может привести пример, это будет здорово.

Ответы [ 3 ]

1 голос
/ 09 июля 2020

Вы можете использовать ItemContainerStyle с DataTrigger в свойстве Count элемента управления ItemsControl Items.

Стиль будет выбирать между двумя разными ContentTemplates, в зависимости от того, есть ли ровно один элемент или нет.

<ItemsControl ItemsSource="{Binding ...}">
    <ItemsControl.Resources>
        <DataTemplate x:Key="DefaultItemTemplate">
            <RadioButton Content="{Binding ...}"/>
        </DataTemplate>
        <DataTemplate x:Key="SingleItemTemplate">
            <Label Content="{Binding ...}"/>
        </DataTemplate>
    </ItemsControl.Resources>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="ContentTemplate"
                    Value="{StaticResource DefaultItemTemplate}"/>
            <Style.Triggers>
                <DataTrigger
                    Binding="{Binding Items.Count,
                              RelativeSource={RelativeSource AncestorType=ItemsControl}}"
                    Value="1">
                    <Setter Property="ContentTemplate"
                            Value="{StaticResource SingleItemTemplate}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>
0 голосов
/ 09 июля 2020

ContentControl создает элемент управления и выбирает для него правильный DataTemplate в зависимости от его типа. Таким образом, вам не нужен конвертер:

    <ContentControl Content="{Binding Child}">
        <ContentControl.Resources>
            <DataTemplate DataType="{x:Type local:Type1}">
                <Label Content="{Binding ItemText}"/>
            </DataTemplate>
            <DataTemplate DataType="{x:Type local:Type2}">
                <ItemsControl ItemsSource="{Binding Items}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <RadioButton Content="{Binding ItemText}"/>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </DataTemplate>
        </ContentControl.Resources>
    </ContentControl>

Этот код реагирует на различные типы свойства Child внутри ВМ:

public BaseType Child { get; set; }

Типы данных:

public class BaseType { }
public class Type1 : BaseType
{
    public string ItemText { get; set; }
}
public class Type2 : BaseType
{
    public ObservableCollection<Type1> Items { get; } = new ObservableCollection<Type1>();
}

например, если вы установите Child на Type1, он покажет вам одну метку

Child = new Type1 { ItemText = "hello" };

или если вы установите его на Type2, у вас будет ваша коллекция радиокнопок:

var t = new Type2();
t.Items.Add(new Type1 { ItemText = "hello" });
t.Items.Add(new Type1 { ItemText = "world" });
Child = t;
0 голосов
/ 09 июля 2020

Попробуйте реализовать такой алгоритм:

  1. ViewModel предоставляет коллекцию в свойстве типа ObservableCollection.
  2. В сетке XAML с наложенными элементами: TextBlock и ItemsControl.
  3. Свойство Count коллекции связывается через триггер с Visibility, Count == 1: TextBlock становится видимым, ItemsControl - скрывается.
  4. В TextBlock свойство Text связано с первым элемент коллекции.
  5. ItemsControl.ItemsSource привязан к коллекции. RadiButton устанавливается в DataTemplate. Для правильной работы RadioButtons в RadioButton.GroupName укажите любое имя группы.

Пример. ViewModel:

using System.Collections.ObjectModel;

namespace LabelOrRadioButton
{
    public class ViewModel
    {

        public ObservableCollection<string> Strings { get; }
            = new ObservableCollection<string>();

        private RelayCommand _addCommand;
        public RelayCommand AddCommand => _addCommand
            ?? (_addCommand = new RelayCommand
            (
                p => Strings.Add((string)p),
                p => p is string val && !string.IsNullOrWhiteSpace(val)
            ));
    }
}

Для Команд используется класс с такой реализацией:

using System;
using System.Windows;
using System.Windows.Input;

namespace LabelOrRadioButton
{
    /// <summary>Executing Delegate.</summary>
    /// <param name="parameter">Command parameter.</param>
    public delegate void ExecuteHandler(object parameter);
    /// <summary>CanExecuting Delegate.</summary>
    /// <param name="parameter">Command parameter.</param>
    /// <returns><see langword="true"/> - if command execution is allowed.</returns>
    public delegate bool CanExecuteHandler(object parameter);

    /// <summary>A class implementing the ICommand interface for creating WPF commands.</summary>
    public class RelayCommand : ICommand
    {
        private readonly CanExecuteHandler _canExecute = CanExecuteDefault;
        private readonly ExecuteHandler _execute;
        private readonly EventHandler _requerySuggested;

        public event EventHandler CanExecuteChanged;

        /// <summary>The constructor of the command.</summary>
        /// <param name="execute">Command Executable Method.</param>
        /// <param name="canExecute">Team Status Method.</param>
        public RelayCommand(ExecuteHandler execute, CanExecuteHandler canExecute = null)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));

            _canExecute = canExecute;

            _requerySuggested = (o, e) => Invalidate();
            CommandManager.RequerySuggested += _requerySuggested;
        }

        /// <summary>The method of invoking an event about a change in command status.</summary>
        public void Invalidate() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);

        public bool CanExecute(object parameter) => _canExecute == null ? true : _canExecute.Invoke(parameter);

        public void Execute(object parameter) => _execute?.Invoke(parameter);

        /// <summary>Default CanExecute Method/</summary>
        /// <param name="parameter">>Command parameter.</param>
        /// <returns>Is always <see langword="true"/>.</returns>
        public static bool CanExecuteDefault(object parameter) => true;
    }

}

Окно XAML:

<Window x:Class="LabelOrRadioButton.TbItmContWind"
        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:LabelOrRadioButton"
        mc:Ignorable="d"
        Title="TbItmContWind" Height="450" Width="800">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <StackPanel>
            <TextBlock Text="Text to add:" HorizontalAlignment="Center"/>
            <TextBox x:Name="textBox"/>
            <Button Content="Add" Margin="10"
                    Command="{Binding AddCommand, Mode=OneWay}"
                    CommandParameter="{Binding Text, ElementName=textBox}"/>
        </StackPanel>
        <Grid Grid.Column="1">
            <TextBlock Text="{Binding Strings[0]}">
                <TextBlock.Style>
                    <Style TargetType="TextBlock">
                        <Setter Property="Visibility" Value="Hidden"/>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Strings.Count}" Value="1">
                                <Setter Property="Visibility" Value="Visible"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </TextBlock.Style>
            </TextBlock>
            <ItemsControl ItemsSource="{Binding Strings}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <RadioButton GroupName="MyGroup" Content="{Binding}"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
                <ItemsControl.Style>
                    <Style TargetType="ItemsControl">
                        <Setter Property="Visibility" Value="Visible"/>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Strings.Count}" Value="1">
                                <Setter Property="Visibility" Value="Hidden"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </ItemsControl.Style>
            </ItemsControl>
        </Grid>
    </Grid>
</Window>
...