Reputation: 79
Enable button_A when button_B is enabled and image source has a specific .png icon
I have two Buttons
and an Image
object in a WPF application built with .NET Core and C#. What I want on the bottom line is to enable Button_A
only when the Button_B
is enabled and the Image
has a specific .png icon of a checkmark. For those three objects an MVVM model exists. More details in the code below,
XAML file
<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 file - MVVM model
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));
}
}
}
What I tried so far is based on this similar question I asked in the past. A relevant answer posted in the attached question is the use of IMultiValueConverter
. However, I am not confident to figure out how to properly use the Converter for my task.
(The code below won't work)
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>
[EDIT]--example of an 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;
}
}
Upvotes: 0
Views: 591
Reputation: 602
Better approach: I understand "WHAT" you need but , I am not sure "WHY" you need this. There are better ways to enable a button. I also notice that you are using button click which is obviously code behind. When you have MVVM model, try to use ICommand and attach to the "command" property of the button. If you do that , then you can easily assign a delegate to "CanExecute" to make the enabling of the button.
Solution to current problem: Regardless of the above suggestion, solution to your current problem is as below.
The below line in your converter is wrong. This returns object[] again. Basically, you receive an array from the XAML and return the same again. You need to receive the array, process it and return a result (which is "bool" in your case : to enable a button).
return ((bool)values[0]=true, (ImageSource)values[1]=new BitmapImage(new Uri("/Assets/checkmark.png", UriKind.Relative)));
So, do the validation like below..
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 );
}
UPDATE: In case, you use an ICommand (and return a delegatecommand), then you can follow below approach.
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 );
}
then, you don't need converter..
Upvotes: 1