Question

I have a rectangle which I want to set 4 different icons to based on if a value inside my page.cs is between certain values, for instance:

If value is 0 show icon 1.
if value is larger than 0 but smaller or equal to 0.25 show icon 2.
If value is >0.25 && value is <=0.5 show icon 3.
If value is >0.5 && value is <=0.75, show icon 4.
and If value is >0.75 && value is <=1 show icon 5.

Here's what my variable looks like:

private double _double = 0.25;
    public double Volume
    {
        get
        {
            return _double;
        }
        set
        {
            _double = value;
            OnPropertyChanged("Volume");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

I also have INotifyPropertyChanged set next to the partial class

And here's the converter I'm using:

[ValueConversion(typeof(double), typeof(int))]
public class VolumePicture : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (System.Convert.ToDouble(value) <= 0.25)
        {
            return 1;
        }
        else if (System.Convert.ToDouble(value) > 0.25 && System.Convert.ToDouble(value) <= 0.5)
        {
            return 2;
        }
        else if (System.Convert.ToDouble(value) > 0.5 && System.Convert.ToDouble(value) <= 0.75)
        {
            return 3;
        }
        else if (System.Convert.ToDouble(value) > 0.75 && System.Convert.ToDouble(value) <= 1)
        {
            return 4;
        }
        else
        {
            return 0;
        }
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

It basically takes an input and does exactly how I described in the first part.

Aaaand here's the XAML I have for the rectangle which I want to change the opacitymask for:

<Rectangle Height="20" Margin="0,2,0,0">
                <Rectangle.Style>
                    <Style TargetType="{x:Type Rectangle}">
                        <Setter Property="Fill" Value="#FF929292" />
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding IsMouseOver, ElementName=VolumeButton}" 
                                Value="True">
                                <Setter Property="Fill" Value="White" />
                            </DataTrigger>
                            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=NowPlaying.Volume, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource VolumePictureConverter}}" Value="5">
                                <Setter Property="OpacityMask">
                                    <Setter.Value>
                                        <VisualBrush Visual="{StaticResource appbar_sound_mute}"/>
                                    </Setter.Value>
                                </Setter>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=NowPlaying.Volume, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ResourceKey=VolumePictureConverter}}" Value="1">
                                <Setter Property="OpacityMask">
                                    <Setter.Value>
                                        <VisualBrush Visual="{StaticResource appbar_sound_0}"/>
                                    </Setter.Value>
                                </Setter>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=NowPlaying.Volume, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ResourceKey=VolumePictureConverter}}" Value="2">
                                <Setter Property="OpacityMask">
                                    <Setter.Value>
                                        <VisualBrush Visual="{StaticResource appbar_sound_1}"/>
                                    </Setter.Value>
                                </Setter>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=NowPlaying.Volume, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ResourceKey=VolumePictureConverter}}" Value="3">
                                <Setter Property="OpacityMask">
                                    <Setter.Value>
                                        <VisualBrush Visual="{StaticResource appbar_sound_2}"/>
                                    </Setter.Value>
                                </Setter>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=NowPlaying.Volume, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ResourceKey=VolumePictureConverter}}" Value="4">
                                <Setter Property="OpacityMask">
                                    <Setter.Value>
                                        <VisualBrush Visual="{StaticResource appbar_sound_3}"/>
                                    </Setter.Value>
                                </Setter>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Rectangle.Style>
            </Rectangle>

This might look quite messy and for that, I'm sorry.

But, here's my problem: When I change the Volume variable during runtime, nothing seems to happen. I think it's the converter that's not firing, but I have NO idea why this is happening(!) And since I'm really not that good with binding and converters and WPF in general, I've gotten stuck with this..

Anyone got an idea about what the troublemaker might be?

Thank you

One thing to note is that I didn't always have the "NowPlaying.Volume" path in there, I just tried a bunch of stuff. And when I'm debugging I'm getting this in the output (which gets renamed to "Path error: 'Volume'" when I remove the Nowplaying.

System.Windows.Data Error: 40 : BindingExpression path error: 'NowPlaying' property not found on 'object' ''Rectangle' (Name='')'. BindingExpression:Path=NowPlaying.Volume; DataItem='Rectangle' (Name=''); target element is 'Rectangle' (Name=''); target property is 'NoTarget' (type 'Object')
Was it helpful?

Solution

It seems that you are binding to the Rectangle instead of it's DataContext. Rectangle doesn't have property Volume, hence you'll get binding error. Try to change your binding statement to something like this (notice this part : ...Path=DataContext.Volume...) :

<Rectangle.Style>
    <Style TargetType="{x:Type Rectangle}">
        .......
        <Style.Triggers>
            .......
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=DataContext.Volume, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource VolumePictureConverter}}" 
                    Value="5">
                <Setter Property="OpacityMask">
                    <Setter.Value>
                        <VisualBrush Visual="{StaticResource appbar_sound_mute}"/>
                    </Setter.Value>
                </Setter>
            </DataTrigger>
            .......
        </Style.Triggers>
        .......
    </Style>
</Rectangle.Style>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top