Добавить индикатор прогресса в DataTemplate ListBox ItemTemplate в WPF, но не существует в текущем контексте?

Я бы хотел установить индикатор выполнения на клике в моем UserControl на IsIndeterminate = "True", если я нажму на кнопку StartScan.

У меня есть следующий xaml в моем usercontrol:

<ListBox Grid.Column="0" Grid.Row="0" x:Name="myList" HorizontalContentAlignment="Stretch">
    <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid Margin="0,2">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="auto" />
                        <ColumnDefinition Width="auto" />
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" Text="{Binding Name}" />
                    <Button x:Name="StartScan" Grid.Column="1" Click="Start_Click" Margin="20,0,0,0">Start</Button>
                    <ProgressBar Name="pbStatus" Grid.Column="2" Height="22" Minimum="0" Maximum="100" IsIndeterminate="True" />
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
</ListBox>

но все, что я получаю, это то, что psbStatus does not exist in the current context , это теперь прошло после того, как я добавил: ProgressBar pbStatus = new ProgressBar(); в мой пользовательский контроль.

Но я все еще не могу получить доступ к таким свойствам, как IsIndeterminate или Visibility. Например, чтобы показать или скрыть индикатор выполнения.

Всего 1 ответ


Он находится в DataTemplate, поэтому он не существует в коде позади, как это делают обычные элементы управления. Что вы можете сделать, это немного изменить этот шаблон и делать все в XAML. Это моя попытка:

<ListBox Grid.Column="0" Grid.Row="0" x:Name="myList" HorizontalContentAlignment="Stretch" ItemsSource="{Binding Items}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid Margin="0,2">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="auto" />
                    <ColumnDefinition Width="auto" />
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Text="{Binding Name}" />
                <ToggleButton x:Name="StartScan" Grid.Column="1" Margin="20,0,0,0" Content="Start" IsChecked="False"/>
                <ProgressBar Name="pbStatus" Grid.Column="2" Height="22" Width="50" Minimum="0" Maximum="100">
                    <ProgressBar.Style>
                        <Style TargetType="ProgressBar">
                            <Setter Property="IsIndeterminate" Value="False"/>
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding IsChecked, ElementName=StartScan}" Value="True">
                                    <Setter Property="IsIndeterminate" Value="True"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </ProgressBar.Style>
                </ProgressBar>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Здесь я добавляю стиль в индикатор выполнения. Этот стиль определяет DataTrigger, который связан с ToggleButton.IsChecked. Как видите, я изменил с Button на ToggleButton, так как ToggleButton предоставляет свойство IsChecked. Всякий раз, когда я проверяю кнопку, я устанавливаю IsIndeterminate в True.

РЕДАКТИРОВАТЬ - без использования xaml и делать это в коде позади.

<ListBox Grid.Column="0" Grid.Row="0" x:Name="myList" HorizontalContentAlignment="Stretch" ItemsSource="{Binding Items}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid Margin="0,2">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="auto" />
                    <ColumnDefinition Width="auto" />
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Text="{Binding Name}" />
                <Button x:Name="StartScan" Grid.Column="1" Margin="20,0,0,0" Content="Start" Click="StartScan_Click"/>
                <ProgressBar Name="pbStatus" Grid.Column="2" Height="22" Width="50" Minimum="0" Maximum="100"/>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Мы удаляем все триггеры и сохраняем определение XAML, как вы это сделали. В методе события мы должны получить шаблонного родителя. Это предъявитель контента в нашем случае, так как элемент отображается в ListBox. После этого мы должны получить шаблон и, наконец, получить экземпляр индикатора выполнения из шаблона. После этого это просто, так как включает в себя обычную логику.

private void StartScan_Click(object sender, RoutedEventArgs e)
{
    // This is the button
    var btn = sender as Button;

    // Now we get the template that the button is in.
    var contentPresenter = (btn.TemplatedParent as ContentPresenter);

    // Finally we find the progress by its name in the template. Also we have to pass the content
    // presenter as the second argument since this is where the actual instance of the control is.
    var progress = contentPresenter.ContentTemplate.FindName("pbStatus", contentPresenter) as ProgressBar;

    // Do your logic normally as you would.
    progress.IsIndeterminate = !progress.IsIndeterminate;
    btn.Content = progress.IsIndeterminate ? "Stop" : "Start";
}

Есть идеи?

10000