【问题标题】:Disable Buttons in a ListView's DataTemplate禁用 ListView 的 DataTemplate 中的按钮
【发布时间】:2015-10-19 12:52:02
【问题描述】:

假设我有一个简单的小 WPF 应用程序,如下所示:

-------------------------------
Amount Left: 1,000
[Subtract 1]
[Subtract 5]
[Subtract 15]
[Subtract 30]
-------------------------------

“剩余金额:”和“1,000”是独立的文本块。 “减去 x”是 ListView 内、DataTemplate 内的所有按钮。每次单击按钮时,都会从 1,000 中减去按钮的数量。所有这些我都在工作。

这是我无法弄清楚的。当剩余金额低于 30 时,需要禁用最后一个按钮。当数量低于 15 时,倒数第二个按钮将被禁用。依此类推,直到剩余金额为零并且所有按钮都被禁用。我不知道如何禁用按钮。

我在这里给出的这个例子并不是我想要做的完全,但它是一个大大简化的例子,这将使这篇文章变得更短更简单。本质上,这就是我现在所拥有的。

XAML:

<DockPanel>
    <TextBlock Text="Amount Left:" />
    <TextBlock x:Name="AmountLeft" Text="1,000.00" />
</DockPanel>
<DockPanel>
    <ListBox x:Name="AuthorListBox">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Button x:Name="SubButtom" Content="{Binding SubtractAmount}" Click="clickSubtract" />
            <DataTemplate>
    </ListBox>
</DockPanel>

XAML.cs

    private void clickSubtract(object sender, RoutedEventArgs e)
    {
        Button button = sender as Button;
         Int32 SubtractAmount = ((Data.AppInformation)button.DataContext).SubtractAmount;  // This is the amount to be subtracted
        // logic to update the amount remaining.  This works.
        //  What I need to figure out is how to disable the buttons
    }

【问题讨论】:

  • 你在使用 MVVM 吗?这可以在虚拟机中轻松完成
  • 我会发布一个 MVVM 解决方案
  • 天啊!现在可以粘贴 XAML 了吗?
  • 发布整个 XAML,因为我们必须找出问题出在哪里。
  • 你确定它没有达到断点吗?你在调试模式吗?你的 ShellViewModel 在做什么?

标签: c# wpf listview button datatemplate


【解决方案1】:

我将继续创建一个转换器并绑定按钮的 IsEnabled 属性。传递值并执行逻辑。

命名空间

System.Windows.Data

System.Globalization

代码

 public class IsEnabledConverter : IValueConverter
 {
  public object Convert(object value, Type targetType, 
    object parameter, CultureInfo culture)
  {
    // Do the logic
  }

    public object ConvertBack(object value, Type targetType, 
    object parameter, CultureInfo culture)
   {
    // Do the Logic
   }
}

XAML

像这样添加资源

<Window.Resources>
    <local:IsEnabledConverter  x:Key="converter" />
</Window.Resources>

<Button x:Name="SubButtom" IsEnabled="{Binding Value, Converter=   {StaticResource  converter}}" Content="{Binding SubtractAmount}" Click="clickSubtract" />

您可以从以下链接了解转换器

http://wpftutorial.net/ValueConverters.html

当您使用 Converter 构建类时,所有 Xaml 错误都会消失。

【讨论】:

【解决方案2】:

您最好的选择是在视图模型上使用命令而不是点击事件处理程序:

public ICommand SubtractCommand = new DelegateCommand<int>(Subtract, i => i <= AmountLeft);

private void Subtract(int amount)
{
    AmountLeft = AmountLeft - amount;
}

XAML:

<ListBox x:Name="AuthorListBox">
    <ListBox.ItemTemplate>
        <DataTemplate>
                <Button x:Name="SubButtom" Content="{Binding SubtractAmount}"
                        Command="{Binding SubtractCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}"
                        CommandParameter="{Binding SubtractAmount}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

【讨论】:

  • 谢谢格伦。几件事。你能解释一下吗:AncestorType=DataGrid?此外,虽然我知道“EnoughAvailable”是一个布尔值,并且我在 ViewModel 中设置它,但我不知道如何从给定按钮中获取数量并进行比较。还有,当一个按钮被点击时,进行比较的方法是如何被触发的?
  • 我没有完全理解问题,我已经改变了答案
  • 好的,谢谢。我已经有减法部分工作了。我上班时遇到的麻烦是当数量低于它们的数量时禁用按钮。
  • DelegateCommand 的第二个参数是一个函数,它将根据返回 true 或 false 来启用/禁用按钮。它将自动更新 IsEnabled。
  • 所有按钮都会这样做吗?还是只点击一次?
【解决方案3】:

您可以使用MVVM 来完成,方法是为您的按钮ViewModels 设置一个IsEnabled 属性。使用这种方法,您将不需要像当前使用单击事件处理程序那样的任何“代码隐藏”。

Xaml:

<Grid>
    <StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Amount Left:" />
            <TextBlock Text="{Binding CurrentAmount}" />
        </StackPanel>
        <ListBox ItemsSource="{Binding Buttons}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Button Command="{Binding SubtractCommand}" Width="200" Height="75" x:Name="SubButtom" Content="{Binding SubtractAmount}"  IsEnabled="{Binding IsEnabled}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </StackPanel>
</Grid>

Xaml.cs:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }
}

我们希望主ViewModel 有一个Button ViewModels 列表。

ButtonViewModel.cs:

namespace WpfApplication1
{
    public class ButtonViewModel : INotifyPropertyChanged
    {
        private bool _isEnabled;
        private ViewModel _viewModel;

        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                _isEnabled = value;
                OnPropertyChanged();
            }
        }

        public int SubtractAmount { get; set; }

        public ICommand SubtractCommand { get; private set; }

        public ButtonViewModel(ViewModel viewModel)
        {
            _viewModel = viewModel;
            IsEnabled = true;

            SubtractCommand = new CommandHandler(() =>
            {
                _viewModel.CurrentAmount -= SubtractAmount;
            }, true);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class CommandHandler : ICommand
    {
        private readonly Action _action;
        private readonly bool _canExecute;

        public CommandHandler(Action action, bool canExecute)
        {
            _action = action;
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            _action();
        }
    }
}

现在是主要的ViewModel

ViewModel.cs:

namespace WpfApplication1
{
    public class ViewModel : INotifyPropertyChanged
    {
        private int _currentAmount;

        public int CurrentAmount
        {
            get { return _currentAmount; }
            set
            {
                _currentAmount = value;
                OnPropertyChanged();

                if (Buttons != null)
                {
                    foreach (var button in Buttons)
                    {
                        if ((value - button.SubtractAmount) <= 0)
                        {
                            button.IsEnabled = false;
                        }
                    }
                }
            }
        }
        public List<ButtonViewModel> Buttons { get; private set; }

        public ViewModel()
        {
            CurrentAmount = 1000;

            Buttons = new List<ButtonViewModel>
            {
                new ButtonViewModel(this)
                {
                    SubtractAmount = 1
                },
                new ButtonViewModel(this)
                {
                    SubtractAmount = 5
                },
                new ButtonViewModel(this)
                {
                    SubtractAmount = 15
                },
                new ButtonViewModel(this)
                {
                    SubtractAmount = 30
                }
            };
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

如您所见,每个 Button ViewModel 将使用命令减少 CurrentAmount(比点击事件更受欢迎的方法)。每当CurrentAmount 更改时,主ViewModel 会执行一些简单的逻辑,这将禁用相关按钮。

这是经过测试并且有效的。如果您有任何问题,请告诉我。

【讨论】:

  • 哇!你做得非常快。谢谢你。现在我将尝试弄清楚如何将其实施到我已经在做的事情中。
  • @CaseyCrookston 没问题!也许从头开始创建一个演示 WPF 应用程序并复制/粘贴我提供的代码。您可以尝试一下,以帮助您更多地了解它是如何工作的。
  • 是的,我可能会这样做。我真的希望这会简单得多。所有这些都是公司在工作申请过程中发送给我的练习。他们知道我在 WPF 方面的经验为零,但还是要求我尝试一下。他们给我发了一个大约完成了 80% 的 WPF 解决方案,并给了我完成其余部分的步骤。我已经完成了他们要求我做的所有任务,除了这个。我需要尝试弄清楚如何将你给我的东西合并到我已经拥有的东西中。
  • 我想你只要把它粘贴到谷歌上就会给你答案,包括命名空间'using System.Runtime.CompilerServices;' 'CallerMemberName' 用于从其调用处获取属性名称或方法名称。
  • 好的,该应用程序运行良好。谢谢!现在我会花一些时间来理解它,然后让它在我的实际应用中运行。
猜你喜欢
  • 2012-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-30
  • 1970-01-01
  • 2020-01-15
  • 2011-03-04
相关资源
最近更新 更多