简体   繁体   English

使用 WPF,如何以编程方式禁用在 XAML 中为 Listview 控件创建的按钮?

[英]Using WPF, how can I programmatically disable buttons that were created in XAML for a Listview control?

I created a WPF Listview and is populated with instances of ProductCategory.我创建了一个 WPF 列表视图,并填充了 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.接下来我创建列表,填充它并将其分配给 Listview 控件。

private List myProductList = new List();私有列表 myProductList = new List();

// add some items to myProductList // 添加一些项目到 myProductList

// assign product list to ItemsSource property of a ListView // 将产品列表分配给 ListView 的 ItemsSource 属性

myListView.ItemsSource = myProductList; myListView.ItemsSource = myProductList;

In the XAML code, a button labelled "Edit" is added to each row.在 XAML 代码中,每行都添加了一个标有“编辑”的按钮。 Each row represents an instance of ProductCategory:每行代表 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.当用户单击该按钮时,将出现一个对话框,用户可以编辑 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.此时我想禁用 Listview 中的所有按钮。 How could I programmatically achieve this goal?我怎样才能以编程方式实现这个目标?

The buttons are not accessible in myListView.ItemsSource.这些按钮在 myListView.ItemsSource 中不可访问。

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. Button_Click 来自我添加的按钮,因此我可以从某个地方开始。 Executing the code from within the constructor after IntializeComponent() should give you a list of all your buttons在 IntializeComponent() 之后从构造函数中执行代码应该会为您提供所有按钮的列表

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;
}

From the suggested solutions, here is the code to solve my problem:从建议的解决方案中,这里是解决我的问题的代码:

    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;
    }

    private void disableEditButtonsInListView()
    {
        myListView.Items.Cast<dynamic>().ToList().ForEach(item =>
        {
            var myListViewItem = (ListViewItem)(myListView.ItemContainerGenerator.ContainerFromItem(item));
            Button editButton = FindVisualChild<Button>(myListViewItem);
            if (editButton != null)
            {
                editButton.IsEnabled = false;
            }
        });
    }

This is very easy to do using MVVM.使用 MVVM 很容易做到这一点。
I'm showing a simple example - it breaks MVVM somewhat, but will give you an idea of how it should work.我展示了一个简单的例子——它在某种程度上打破了 MVVM,但会让你了解它应该如何工作。

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 . BaseInpc 和 RelayCommand 类

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何以编程方式滚动 WPF 列表视图? - How can I programmatically scroll a WPF listview? 如何在XAML中为WPF ListView禁用某些项目 - How to disable some items in XAML for a WPF ListView 按钮是使用stringbuilder在后面的代码中创建的。 如何使它们调用函数? - Buttons were created using stringbuilder in code behind. How can I make them call functions? 如何在WPF代码中以编程方式实现这一行XAML? - How can I implement this one line XAML programmatically in WPF code? 如何使用XAML和后面的代码序列化WPF用户控件 - How can I serialize wpf user control with xaml and code behind 如何使用XAML中的另一个自定义控件基类使WPF在视图中实例化一个自定义控件? - How can I make WPF instantiate a custom control in my view, using another custom control base class in my XAML? 如何使用C#以编程方式在WPF中创建一个包含字符串的ListView,该字符串包含行和列? - How can I programmatically create a ListView full of strings containing columns and rows in WPF using C#? 如何将ListView控件置于WPF中的其他控件之上 - How I can bring ListView control in top of other controls in WPF 如何在不使用xaml的情况下自动在wpf中创建堆栈面板 - How can I create stackpanels in wpf automatically without using xaml 如何使用 WPF XAML 获得插入阴影 - How can I get an inset drop shadow using WPF XAML
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM