简体   繁体   中英

Invalidate Thumb position when IsDirectionReversed changes

I'm using a slider control in a C# WPF application and want to offer the ability for users to invert the control on the fly.

I've already established that the slider control has a built in IsDirectionReversed property which works well for changing the direction of the control (effectively swapping its minimum and maximum values to opposite ends of the control). However, when the property is changed on the fly, the thumb position remains where it is (visually implying an incorrect value) but its value remains the same (as I would expect).

必要行为的例子

(After inverting the control, clicking anywhere on the track causes the thumb to update to either +1 or -1 of its current value but repositions the thumb into its correct visual position)

Can anyone suggest a way of forcing the thumb to update its position when the inverted property is changed?

XAML

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="MainWindow" Height="139" Width="303">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="10"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="10"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="10"/>
        </Grid.ColumnDefinitions>

        <Slider Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Name="SliderControl" HorizontalAlignment="Left" VerticalAlignment="Top" Width="276" IsDirectionReversed="{Binding Inverted}" Maximum="100" Minimum="1" SmallChange="1"/>

        <TextBlock Grid.Row="2" Grid.Column="1" Text="Value:" HorizontalAlignment="Left" VerticalAlignment="Top" />
        <TextBlock Grid.Row="2" Grid.Column="2" Text="{Binding ElementName=SliderControl, Path=Value}" HorizontalAlignment="Left" VerticalAlignment="Top"/>

        <TextBlock Grid.Row="3" Grid.Column="1" Text="Inverted:" HorizontalAlignment="Left" VerticalAlignment="Top" />

        <TextBlock Grid.Row="3" Grid.Column="2" Text="{Binding ElementName=SliderControl, Path=IsDirectionReversed}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
        <Button Grid.Row="4" Grid.Column="2" Content="Flip!" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    </Grid>
</Window>

C#

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public bool mSliderInverted = false;

    public bool Inverted
    {
        get
        {
            return mSliderInverted;
        }
    }

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        mSliderInverted = !mSliderInverted;
        OnPropertyChanged("Inverted");
    }

    protected void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, e);
    }

    protected void OnPropertyChanged(string propertyName)
    {
        OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

It seems flipping the IsDirectionInversed property doesn't cause the control to rerender, I'd say this is a bug in WPF (Bug in WPF!? No way!).

By trial and error, I discovered that if you invalidate the PART_Track part of the slider (The element that contains the RepeatButtons and the Thumb), it magically switches it around and everything works the way it should!

So if you just modify your Button_Click handler to look like this, everything should work just fine. :-)

private void Button_Click(object sender, RoutedEventArgs e)
{
    mSliderInverted = !mSliderInverted;
    OnPropertyChanged("Inverted");

    // Retrieve the Track from the Slider control
    var track = SliderControl.Template.FindName("PART_Track", SliderControl) as Track;

    // Force it to rerender
    track.InvalidateVisual();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM