0

I am trying to learn how to use the IValueConverter to enable/disable controls (in this case a button) using the boolean-property of an item selected in a listbox. The button in question is the "TestButton". I believe I have the XAML for it setup correctly but it does not enable when I add and select a user defined item or disable when I select one of the other items in the listbox. The listbox contains a list of "Drink" objects that can be added to. When one is added it becomes a user defined item. Now I believe I am missing something but I am not sure what. Any help will be appreciated.

ViewModel code here:

<Window x:Class="WpfApp1.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:local="clr-namespace:WpfApp1"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Window.Resources>
    <local:Drinks x:Key="Drink"/>
    <local:EnableConverter x:Key="EnableConverter"/>

    <BooleanToVisibilityConverter x:Key="BoolToVis"/>

    <ControlTemplate x:Key="validationTemplate">
        <DockPanel>
            <TextBlock Foreground="Red" FontSize="20">!</TextBlock>
            <AdornedElementPlaceholder/>
        </DockPanel>
    </ControlTemplate>

    <Style x:Key="textStyleTextBox" TargetType="TextBox">
        <Setter Property="Foreground" Value="#333333" />
        <Setter Property="MaxLength" Value="40" />
        <Setter Property="Width" Value="392" />
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
                <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <ListBox x:Name="DrinksListBox" HorizontalAlignment="Center" Height="325" Width="275" Margin="0,0,0,0" VerticalAlignment="Center" Grid.Column="0" ItemsSource="{Binding SomeDrinks}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid Margin="0,2">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding Type}" Width="80"  Margin="0,0,10,0" Grid.Column="0"/>
                    <TextBlock Text="{Binding Name}" Width="80"  Margin="0,0,10,0" Grid.Column="1" HorizontalAlignment="Left"/>
                    <TextBlock Text="{Binding NumberOfCans}" Width="80"  Margin="0,0,10,0" Grid.Column="2" HorizontalAlignment="Left"/>
                    <Button x:Name="DrinkDeleteButton" Content="Delete" Visibility="{Binding Path=IsUserDefined, Converter={StaticResource BoolToVis}}" Click="CmdDeleteDrink_Clicked" HorizontalAlignment="Left" Grid.Column="3"/>
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

    <TextBox x:Name="DrinkNameTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="45" Margin="0,0,0,100" TextWrapping="Wrap" Text="Enter Drink Name" VerticalAlignment="Center" Width="240" FontSize="20" VerticalContentAlignment="Center"/>

    <TextBox x:Name="NumberCansTextBox" Style="{StaticResource textStyleTextBox}" Grid.Column="1" HorizontalAlignment="Left" Height="45" Margin="0,0,0,150" VerticalAlignment="Bottom" Width="240" FontSize="20" VerticalContentAlignment="Center">
        <TextBox.Text>
            <Binding Path="NumberOfCans" UpdateSourceTrigger="PropertyChanged" Source="{StaticResource Drink}">
                <Binding.ValidationRules>
                    <local:NumberCansValidationRule Min="0" Max="10"/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>

    <ComboBox x:Name="DrinkTypeComboBox" Grid.Column="1" HorizontalAlignment="Left" Margin="0,47,0,0" VerticalAlignment="Top" Width="240" Height="45" ItemsSource="{Binding Drinks,  Mode=OneWay}" DisplayMemberPath="Type" FontSize="20"/>
    <Button x:Name="AddDrinkButton" Content="Add Drink" Grid.Column="1" HorizontalAlignment="Right" Margin="0,0,10,100" VerticalAlignment="Center" Width="100" Height="45" Click="CmdAddDrink_Clicked">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Setter Property="IsEnabled" Value="False"/>
                <Style.Triggers>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Path=(Validation.HasError), ElementName=NumberCansTextBox}" Value="False"/>
                        </MultiDataTrigger.Conditions>
                        <Setter Property="IsEnabled" Value="True"/>
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>
    <Button x:Name="TestButton" Content="Test" IsEnabled="{Binding Path=IsUserDefined, UpdateSourceTrigger=PropertyChanged, Source={StaticResource Drink}, Converter={StaticResource EnableConverter}}" Grid.Column="1" HorizontalAlignment="Right" Margin="0,70,10,0" VerticalAlignment="Center" Width="100" Height="45"/>
</Grid>

Here is my converter:

namespace WpfApp1
{
    class EnableConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            bool isenable = false;
            bool b = (bool)value;

            if (b == true)
            {
                isenable = true;
            }
            return isenable;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

This class contains the "IsUserDefined" property that I am binding to:

public class Drinks
{
    private string type;
    private string name;
    private int numCans;

    public Drinks() { }

    public Drinks(string type, string name, int numCans)
    {
        this.type = type;
        this.name = name;
        this.numCans = numCans;
    }

    public bool IsUserDefined { get; set; }

    public string Type
    {
        get { return type; }

        set
        {
            if (type != value)
            {
                type = value;
            }
        }
    }

    public string Name
    {
        get { return name; }

        set
        {
            if (name != value)
            {
                name = value;
            }
        }
    }

    public int NumberOfCans
    {
        get { return numCans; }

        set
        {
            if (numCans != value)
            {
                numCans = value;
            }
        }
    }
}
DevMent
  • 55
  • 5
  • Possible duplicate of [WPF BooleanToVisibilityConverter that converts to Hidden instead of Collapsed when false?](https://stackoverflow.com/questions/3128023/wpf-booleantovisibilityconverter-that-converts-to-hidden-instead-of-collapsed-wh) – Xiaoy312 Oct 11 '18 at 19:22
  • 3
    As a note, your EnableConverter does nothing sensible. It converts from bool to bool, false to false and true to true. – Clemens Oct 11 '18 at 19:30
  • Button IsEnabled can be directly bound to the IsUserDefined variable. No converter is needed. – phabtar Oct 11 '18 at 22:59
  • @phabtar - should removing just the converter from the IsEnabled property in the button work? – DevMent Oct 12 '18 at 12:51
  • @phabtar - I tried removing the converter from the IsEnabled property and just binding it like you mentioned but it didn't work. Could you provide an example, please? – DevMent Oct 12 '18 at 13:00
  • @DevMent I assume you are changing "isUserDefined" of Drinks resource in the Window code behind. However the Drinks class isn't notifying changes to it. It must implement INotifyPropertyChanged interface. Have a look at : https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-implement-property-change-notification – phabtar Oct 15 '18 at 00:32
  • @phabtar I added the property change notification interface and modified based on the code in the link which I understand but no success unfortunately – DevMent Oct 15 '18 at 15:09
  • @phabtar I ran across this when I was looking for a solution: – DevMent Oct 15 '18 at 18:10

0 Answers0