【问题标题】:Enable button when certain conditions apply当某些条件适用时启用按钮
【发布时间】:2020-12-02 04:09:03
【问题描述】:

在 button_B 启用且图像源具有特定 .png 图标时启用 button_A

在使用 .NET Core 和 C# 构建的 WPF 应用程序中,我有两个 Buttons 和一个 Image 对象。我想要的底线是仅在启用Button_B 并且Image 具有特定的.png 复选标记图标时启用Button_A。对于这三个对象,存在 MVVM 模型。更多细节在下面的代码中,

XAML 文件

<Window x:Class="MyApp.MainWindow"
        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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
        xmlns:local="clr-namespace:MyApp"
        mc:Ignorable="d"
        Height="1080"
        Width="1920"
        ResizeMode="NoResize">
    <Grid x:Name="MyGrid"
              Background="White"
              HorizontalAlignment="Center"
              ShowGridLines="False">
            <!--Grid Columns-->
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="200"/>
        </Grid.ColumnDefinitions>
        <!--Grid Rows-->
        <Grid.RowDefinitions>
            <RowDefinition Height="45"/>
            <RowDefinition Height="45"/>
        </Grid.RowDefinitions>
        <Button 
            x:Name="Button_A"
            Click="Button_A_Click"
            Content="Execute"
            IsEnabled="{Binding EnableButtonA}"
            HorizontalAlignment="Left"
            Width="80"
            Height="25"
            Margin="135,0,0,0"
            Grid.Column="0"
            Grid.Row="0"/>
        <Button
            x:Name="Button_B"
            Click="Button_B_Click"
            Content="Execute"
            IsEnabled="{Binding EnableButtonB}"
            HorizontalAlignment="Left"
            Width="80"
            Height="25"
            Margin="135,0,0,0"
            Grid.Column="1"
            Grid.Row="1">
        </Button>
        <Image
               x:Name="IconSymbol"
               Source="{Binding Path=ImageChangeSource,UpdateSourceTrigger=PropertyChanged}"
               Grid.Row="1"
               Grid.Column="1"
               Width="{Binding Path=CalculationsImageWidth}"
               Height="Auto"
               HorizontalAlignment="Left"
               Margin="190,0,0,0"
               Visibility="Visible"
               IsEnabled="True"/>
    </Grid>
</Window>

.CS 文件 - MVVM 模型

namespace MyApp
{
    public class CustomViewModel : INotifyPropertyChanged
    {
        //Button B
        private bool _enableButtonB;
        public bool EnableButtonB
        {
            get
            {
                return _enableButtonB;
            }
            set
            {
                _enableButtonB = value;
                OnPropertyChanged("EnableButtonB");
            }
        }
        
        //Image
        private ImageSource _imageChangeSource;
        public ImageSource ImageChangeSource
        {
            get
            {
                return _imageChangeSource;
            }
            set
            {
                _imageChangeSource = value;
                OnPropertyChanged("ImageChangeSource");
            }
        }

        //Image width
        private int _changeImageWidth;
        public int ImageWidth
        {
            get
            {
                return _changeImageWidth;
            }
            set
            {
                _changeImageWidth= value;
                OnPropertyChanged("ImageWidth");
            }
        }
        
        //Button A
        private bool _enableButtonA;
        public bool EnableButtonA
        {
            get
            {
                return _enableButtonA;
            }
            set
            {
                //What to write here?
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string property)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
        }
    }
}

到目前为止我所尝试的都是基于我过去问过的这个similar question。附加问题中发布的relevant answerIMultiValueConverter 的使用。但是,我不确定如何正确使用 Converter 来完成我的任务。

(下面的代码不起作用)

public class EnableReportConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return ((bool)values[0]=true, (ImageSource)values[1]=new BitmapImage(new Uri("/Assets/checkmark.png", UriKind.Relative)));
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new InvalidOperationException();
    }
}
<Button 
    x:Name="Button_A"
    Click="Button_A_Click"
    Content="Execute"
    HorizontalAlignment="Left"
    Width="80"
    Height="25"
    Margin="135,0,0,0"
    Grid.Column="0"
    Grid.Row="0">
    <Button.IsEnabled>
      <MultiBinding>
         <MultiBinding.Converter>
            <local:EnableReportConverter/>
         </MultiBinding.Converter>
         <Binding Path="EnableButtonB"/>
         <Binding Path="ImageChangeSource"/>
      </MultiBinding>
   </Button.IsEnabled>
</Button>

[编辑]--ICommand 示例

public ICommand ButtonACommand
{
    get { return new DelegateCommand<object>(FuncBrowseFileCommand); }
}
public void FuncBrowseFileCommand(object parameters)
{
    var final_result = BrowseFile(FilesFilePath);
    Nullable<bool> browse_result = final_result.browse_result;
    FilesFilePath = final_result.filename;
    
    //below are some MVVM object-- dont pay them attention
    if (browse_result == true)
    {
        EnableFilesLoadButton = true;
        EnableFilesBrowseButton = true;
        EnableFilesViewButton = false;
        FilesPanelVisibility = false;
    }
    else
    {
        FilesImageVisibility = true;
        return;
    }
}

【问题讨论】:

    标签: c# wpf mvvm


    【解决方案1】:

    更好的方法: 我了解您需要“什么”,但是,我不确定“为什么”您需要这个。有更好的方法来启用按钮。我还注意到您正在使用按钮单击,这显然是背后的代码。当您有 MVVM 模型时,尝试使用 ICommand 并附加到按钮的“命令”属性。如果你这样做了,那么你可以很容易地为“CanExecute”分配一个代表来启用按钮。

    当前问题的解决方案:无论上述建议如何,您当前问题的解决方案如下。

    转换器中的以下行是错误的。这将再次返回 object[]。基本上,您从 XAML 接收一个数组并再次返回该数组。您需要接收数组,对其进行处理并返回结果(在您的情况下为“布尔”:启用按钮)。

    return ((bool)values[0]=true, (ImageSource)values[1]=new BitmapImage(new Uri("/Assets/checkmark.png", UriKind.Relative)));
    

    所以,像下面这样进行验证..

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
    //INCOMING DATA
        bool is_buttonB_enabled = (bool)values[0]; //This is the first value in the object array.
    
        ImageSource _image = (ImageSource) values[1]; //This is the second value in the object array.
    
    //YOUR EXPECTED IMAGE.
        ImageSource _expected_image = new BitmapImage(new Uri("/Assets/checkmark.png", UriKind.Relative));
    
    //VALIDATE
        return (is_buttonB_enabled == true && _image == _expected_image );
        }
    

    更新: 如果您使用 ICommand(并返回委托命令),那么您可以遵循以下方法。

        public ICommand ButtonACommand
    {
        get { return new DelegateCommand<object>(FuncBrowseFileCommand,_canEnableButton); }
    }
    
        private bool _canEnableButton(object obj)
    {
    
    //YOUR EXPECTED IMAGE.
        ImageSource _expected_image = new BitmapImage(new Uri("/Assets/checkmark.png", UriKind.Relative));
    
    
    return (EnableButtonB == true && ImageChangeSource == _expected_image );
    
    }
    

    那么,你就不需要转换器了..

    【讨论】:

    • Lingam 非常感谢您的回答。这很好解释。感谢您为在脚本中添加 cmets 所做的努力。我确实对用于替换 Click 属性的每个不同 Button 使用了 ICommand。由于我也收到了关于CanExecute 的类似建议,您能否也仅发布CanExecute 方法的代码?我大多数时候使用 ICommands 但没有 CanExecute() 属性。无论如何,我都会接受并支持您的回答。
    • 请分享一些代码,展示您如何使用 Icommand。您是否使用任何委托命令?如果是这样,我可以展示如何在您的情况下使用它的示例。
    • 是的,让我在上面的问题文本中提供一个示例。检查我的编辑
    • 当您使用时,DelegateCommand 我假设它取自 Prism 或任何其他外部库。所以,我将根据此更新答案。
    • 我直接在答案中输入代码部分。所以,请原谅任何轻微的错别字。我将 _canEnable 方法写为 void。它实际上是一个返回 bool 的函数。所以,请找到更新后的答案。
    猜你喜欢
    • 2015-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-15
    • 2016-04-13
    • 1970-01-01
    • 2016-07-21
    • 1970-01-01
    相关资源
    最近更新 更多