Make a slider use an existing IValueConverter

情到浓时终转凉″ 提交于 2019-12-11 01:20:10

问题


I have a slider implementing System.Windows.Controls.Slider:

class MySlider : Slider
{
    public MySlider()
    {
        Minimum = 1;
        Maximum = 1000;
    }
}

I use it like this: MySlider slider = new MySlider() { Width = 400, Name = "TheSlider"};

It works well, but it is linear.
I want to make it non-linear because sensible values are like 1, 2, 10, 1000 (for instance).
So I defined a non-linear IValueConverter like this:

public class LogScaleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (int)Math.Log((int)value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (int)Math.Exp((double)value);
    }
}

QUESTION: How to make the slider use this converter?


回答1:


UPDATE: Giving you a full working code.

MainWindow.xaml

<StackPanel>
    <StackPanel.Resources>
        <spikes:LogScaleConverter x:Key="LogScaleConverter"/>
    </StackPanel.Resources>
    <TextBox x:Name="InputNumberTextBox" Width="100" Text="{Binding InputNumber, Mode=TwoWay}"/>
    <Slider Width="1000"
            Minimum="1" 
            Maximum="100"
            Value="{Binding ElementName=InputNumberTextBox,Path=Text, Mode=TwoWay,Converter={StaticResource LogScaleConverter}}"/>
</StackPanel>

LogScaleConverter.cs

public class LogScaleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var stringValue = value.ToString();
        if (string.IsNullOrWhiteSpace(stringValue)) return null;

        var intValue = int.Parse(stringValue);
        return Math.Log(intValue);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (int)Math.Exp((double)value);
    }
}

Notice now that when you type something in the textbox it'll change the value of the slider based on your formula. You can put a break point on the Convert and see if that is the value that you really want in the slider.

I don't think it is necessary to create a MySlider class since you are only setting the Minimum and Maximum properties which is already available on the actual object itself. You should only be extending a control if you are creating custom stuff like defining your own Dependency Properties.




回答2:


Make window Resource as

 <Window.Resources>
    <local:LogScaleConverter x:Key="LogScaleConverterInstanse"/>
  </Window.Resources>

Make a TextBox(or any element) <TextBox x:Name="firstName" />

Bind your slider to element

 <Slider Height="23" Name="slider1" Width="100" Value="{Binding Text,ElementName=      firstName,Converter={StaticResource LogScaleConverterInstanse}}"/>



回答3:


I think the issue you are having with the answers is that everyone is assuming (correctly in the case of common WPF usage) that your slider's value is being bound to some other control (textbox for example) or a ViewModel property. In this common case, the converter is applied within the binding (see all other answers) and converts the slider's internal linear value to your logarithmic value.

If you are just using this in a basic application where your code-behind or other application code is actually just polling the slider control directly, then you can use your converter as such:

var logConverter = new LogScaleConverter();
var logValue = logConverter.Convert(mySlider.Value, typeof(double), null, null);

But I have to say that this makes little sense as you could simply use a method or place the conversion in line in your code. Using the converter would only potentially make sense if this is also being used through binding somewhere else in your UI and that converter code might change.

Since you are making a custom control anyway, another approach would be to add a new DependencyProperty to your slider control (maybe call it 'LogSlider.LogValue') that handles this conversion directly:

public partial class LogSlider : Slider
{
    public LogSlider()
    {
        InitializeComponent();


        var metadata = new FrameworkPropertyMetadata();
        metadata.PropertyChangedCallback += ValuePropertyChangedCallback;
        ValueProperty.OverrideMetadata(typeof(LogSlider), metadata);
    }

    public double LogValue
    {
        get { return (double)GetValue(LogValueProperty);}
        set { SetValue(LogValueProperty, (value));}
    }

    public static readonly DependencyProperty LogValueProperty =
        DependencyProperty.Register("LogValue", typeof(double), typeof(LogSlider), new PropertyMetadata(0.0, LogValuePropertyChangedCallback));

    private static void LogValuePropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        dependencyObject.SetValue(ValueProperty, Math.Exp((double)args.NewValue));
    }

    private static void ValuePropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        dependencyObject.SetValue(LogValueProperty, Math.Log((double)args.NewValue));
    }
}

Now you can access the LogValue directly from your custom Slider control as well as bind bidirectionally to it in the UI - with changes to the linear value being reflected in the log and vice versa.




回答4:


 var slider = new MySlider();
    var bnd = new Binding("Text") { ElementName = "firstName" };
    bnd.Converter = new LogScaleConverter();

    slider.SetBinding(Slider.ValueProperty, bnd);


来源:https://stackoverflow.com/questions/20946760/make-a-slider-use-an-existing-ivalueconverter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!