Как получить список элементов управления типа из всего окна? - PullRequest
0 голосов
/ 31 января 2020

У меня есть приложение WPF MVVM, где у меня есть несколько ItemsControls на нескольких уровнях, выглядящих следующим образом:

<ItemsControl Grid.Column="1" ItemsSource="{Binding ElementName=cb_Letter, Path=SelectedItem.Words2}" Name="ICWords2">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Grid >
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="2*"/>
                                    <ColumnDefinition Width="8*"/>
                                </Grid.ColumnDefinitions>
                                <Label Grid.Column="0" Content="{Binding .}" />
                                <TextBox Grid.Column="1"/>
                            </Grid>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>

, и я хочу управлять всеми элементами командой, выполняемой из:

<Button Grid.Column="4" Name="btn_Check" Command="CMDS:Commands.Check"></Button>

In команда:

var parrents = CollectionOfAll<ItemsControl>(Window);
        foreach (var items in parrents)
        {
            foreach (var item in items.Items)
            {
                var child = FindChild<Grid>((UIElement)items.ItemContainerGenerator.ContainerFromItem(item));
                Label lb = child.Children.OfType<Label>().First();
                TextBox tb = child.Children.OfType<TextBox>().First();
                tb.BorderBrush = lb.Content.ToString() == tb.Text.ToString() ? Brushes.Green : Brushes.Red;
            }
        }

Но я новичок в WPF и не могу понять, как получить всех потомков потомков потомков .... и так далее типа

, поэтому TODO:

private List<T> CollectionOfAll<T>(...){...}

Почему я так делаю? Это приложение для раненых детей, чтобы научиться писать на p c, поэтому в ярлыке есть символ или строка, и они должны попытаться написать это в текстовое поле справа от этого ярлыка, а затем я должен проверить, если это правильно

1 Ответ

0 голосов
/ 31 января 2020

Ручной анализ элементов управления в приложении WPF является антипаттерном.

WPF предоставляет более эффективные способы достижения того, что вам нужно, с помощью привязок и шаблонов .

Вы можете использовать Style на каждом TextBox, чтобы WPF автоматически изменил свойство BorderBrush в зависимости от результата равенства между свойством Text и значением DataContext (которое кажется быть типом string в вашем случае).

<ItemsControl ItemsSource="{Binding}">
    <ItemsControl.Resources>
        <local:EqualityConverter x:Key="EqualityConverter"/>
    </ItemsControl.Resources>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid >
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="2*"/>
                    <ColumnDefinition Width="8*"/>
                </Grid.ColumnDefinitions>
                <Label Grid.Column="0" Content="{Binding .}" />
                <TextBox x:Name="textBox" Grid.Column="1">
                    <TextBox.Style>
                        <Style TargetType="TextBox">
                            <Setter Property="BorderBrush" Value="Red" /> <!-- Default color -->
                            <Style.Triggers>
                                <DataTrigger Value="true">
                                    <DataTrigger.Binding>
                                        <MultiBinding Converter="{StaticResource EqualityConverter}">
                                            <Binding RelativeSource="{RelativeSource Mode=Self}" Path="Text"/>
                                            <Binding Path="."/>
                                        </MultiBinding>
                                    </DataTrigger.Binding>
                                    <Setter Property="BorderBrush" Value="Green" /> <!-- Color when values are equal -->
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </TextBox.Style>
                </TextBox>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Вам необходимо определить дополнительный фрагмент кода (a Converter):

/// <summary>
/// Returns true if all passed values are equal.
/// </summary>
public class EqualityConverter : IMultiValueConverter {
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        => values.All(v => v.Equals(values[0]));

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        => throw new NotImplementedException();
}

Устранение проблемы WPF-ориентированным способом

Еще лучший способ достичь желаемого - определить правильную модель вида с самого начала:

public class QuestionViewModel {
    public string RequiredText { get; set; }
    public string InputText{ get; set; }
    public bool IsCorrect => RequiredText.Equals(InputText);
}

(Это должно реализовать INotifyPropertyChanged, но для простоты я не показал этого)

И вы бы связали свой ItemsControl.ItemsSource с набором QuestionViewModel вместо набора string:

<ItemsControl ItemsSource="{Binding Questions}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid >
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="2*"/>
                    <ColumnDefinition Width="8*"/>
                </Grid.ColumnDefinitions>
                <Label Grid.Column="0" Content="{Binding RequiredText}" />
                <TextBox x:Name="textBox" Grid.Column="1" Text="{Binding InputText}">
                    <TextBox.Style>
                        <Style TargetType="TextBox">
                            <Setter Property="BorderBrush" Value="Red" />
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding IsCorrect}"  Value="true">
                                    <Setter Property="BorderBrush" Value="Green" />
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </TextBox.Style>
                </TextBox>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Вероятно, вам следует взглянуть на шаблон MVVM.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...