Home > Mobile >  Using WPF, how can I programmatically disable buttons that were created in XAML for a Listview contr
Using WPF, how can I programmatically disable buttons that were created in XAML for a Listview contr

Time:11-27

I created a WPF Listview and is populated with instances of ProductCategory.

public class ProductCategory
{
    public int Id { get; set; }

    public string CategoryName { get; set; }

    public DateTime CreatedDate { get; set; }

    public DateTime LastUpdated { get; set; }
}

Next I create the list, populate it and assign it to the Listview control.

private List myProductList = new List();

// add some items to myProductList

// assign product list to ItemsSource property of a ListView

myListView.ItemsSource = myProductList;

In the XAML code, a button labelled "Edit" is added to each row. Each row represents an instance of ProductCategory:

    <ListView x:Name="myListView" Height="352" HorizontalAlignment="Left" Margin="20,90,0,0" VerticalAlignment="Top" Width="1008">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Category Name" DisplayMemberBinding="{Binding CategoryName}" Width="200"/>
                <GridViewColumn Header="Created Date" DisplayMemberBinding="{Binding CreatedDate}" Width="200"/>
                <GridViewColumn Header="Last Updated" DisplayMemberBinding="{Binding LastUpdated}" Width="200"/>
                <GridViewColumn Header="Edit" Width="200">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Button Content="Edit" Click="EditCategory" CommandParameter="{Binding}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView>
        </ListView.View>
    </ListView>

When the user clicks the button, a dialog appears and the user can edit the data for an instance of ProductCategory. When the user closes the dialog, the user is returned to the Listview.

At this point I want to disable all the buttons in the Listview. How could I programmatically achieve this goal?

The buttons are not accessible in myListView.ItemsSource.

CodePudding user response:

I created a List to stores the results. You can see that I pick a couple of random buttons from the list and disable them. The Button_Click is from a button that I added so I could have somewhere to start. Executing the code from within the constructor after IntializeComponent() should give you a list of all your buttons

List<Button> buttons = 
    new List<Button>();

private void Button_Click(object sender, RoutedEventArgs e)
{
    myListView.Items
        .Cast<dynamic>()
        .ToList()
        .ForEach(item => {
            var listviewitem = 
               (ListViewItem)             
                   (myListView
                       .ItemContainerGenerator
                           .ContainerFromItem(item));

            Button editbutton = 
                FindVisualChild<Button>
                    (listviewitem);

            buttons
                .Add(editbutton);
        });

    buttons[1]
        .IsEnabled = false;
    buttons[3]
        .IsEnabled = false;
}

private childItem FindVisualChild<childItem>(DependencyObject obj)
    where childItem : DependencyObject
{
    for (int i = 0; 
             i < VisualTreeHelper
                     .GetChildrenCount(obj); 
                         i  )
    {
        DependencyObject child = 
            VisualTreeHelper
                .GetChild(obj, i);

        if (child != null 
               && child is childItem)
        {
            return 
                (childItem)child;
        }
        else
        {
            childItem childOfChild = 
                FindVisualChild<childItem>
                    (child);

            if (childOfChild != null)
                return 
                    childOfChild;
        }
    }
    return null;
}

CodePudding user response:

This is very easy to do using MVVM.
I'm showing a simple example - it breaks MVVM somewhat, but will give you an idea of how it should work.

using Simplified;
using System;
using System.Collections.ObjectModel;
using System.Windows;

namespace Core2022.SO.user2949159
{
    public class ProductsViewModel : BaseInpc
    {
        public ObservableCollection<ProductCategory> Products { get; } = new()
        {
            new ProductCategory() {Id = 1, CategoryName = "Electronics", CreatedDate = DateTime.Now.AddDays(-15).Date, LastUpdated= DateTime.Now.AddDays(-5).Date},
            new ProductCategory() {Id = 2, CategoryName = "Сlothes", CreatedDate = DateTime.Now.AddDays(-7).Date, LastUpdated= DateTime.Now.AddDays(-1).Date}
        };

        private RelayCommand? _editCommand;
        private bool _editingOff;

        public RelayCommand EditCommand => _editCommand ??= new RelayCommand<ProductCategory>(EditExecute, EditCanExecute);

        public bool EditingOff
        {
            get => _editingOff;
            set
            {
                if (Set(ref _editingOff, value))
                    EditCommand.RaiseCanExecuteChanged();
            }
        }
        private bool EditCanExecute(ProductCategory product) => !EditingOff;

        private void EditExecute(ProductCategory product)
        {
            // Some Code for edit product
            MessageBox.Show($"{product.Id}: {product.CategoryName}");
        }
    }
<Window x:Class="Core2022.SO.user2949159.ProductsWindow"
        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:Core2022.SO.user2949159"
        mc:Ignorable="d"
        Title="ProductsWindow" Height="450" Width="800"
        DataContext="{DynamicResource vm}">
    <Window.Resources>
        <local:ProductsViewModel x:Key="vm"/>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <CheckBox Content="Editing Off" IsChecked="{Binding EditingOff}" Margin="5"/>
        <ListView Grid.Row="1" ItemsSource="{Binding Products}" HorizontalAlignment="Left" Margin="20">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Category Name" DisplayMemberBinding="{Binding CategoryName}" Width="200"/>
                    <GridViewColumn Header="Created Date" DisplayMemberBinding="{Binding CreatedDate}" Width="200"/>
                    <GridViewColumn Header="Last Updated" DisplayMemberBinding="{Binding LastUpdated}" Width="200"/>
                    <GridViewColumn Header="Edit" Width="200">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <Button Content="Edit"
                                        CommandParameter="{Binding}"
                                        Command="{Binding EditCommand, Mode=OneWay, Source={StaticResource vm}}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

BaseInpc and RelayCommand classes.

  • Related