简体   繁体   中英

Binding a control to multiple properties in WPF

Firstly i appologise if this question is stupid but i am new to WPF and have gotten into some difficulty with some controls.

I have an Image Editor application, This application has several image minipulation controls like Invert, Rotate, Zoom, Brightness and Contrast.

To edit the controls the user selects the control they would like to edit, eg brightness, and a Slider appears along the side of the image (this is otherwise hidden).

This slider is currently bound directly to a property in my ViewModel for Brightness.

I want to be able to reuse this Slider control but dynamically set the binding so for example when i select the Zoom control, that the same slider will change the Zoom and so on.

Should i use some sort of empty property that is a pointer to another property which can be swapped out as and when i need to?

I'm not familiar with WPF but i'm sure there is a much tidier way to sort this.

Any help would be much appreciate.

Currently what i have looks like this.

XMAL Slider Control

<Slider Grid.Row="0" IsSelectionRangeEnabled="True"  SelectionStart="50" SelectionEnd="150" Grid.Column="1" Orientation="Vertical" Minimum="0" Maximum="200" Value="{Binding Brightness}" Visibility="{Binding IsBrightnessAndContrastEnabled, Converter={StaticResource VisibilityConverter}}">

IsBrightnessAndContrastEnabled is simple a bool to decide wether or not to show the slider,

private int _brightness = 100;
    public int Brightness
    {
        get {  return _brightness;}
        set
        {
            if (_brightness != value)
            {
                Set(() => Brightness, ref _brightness, value);
                ChangeBrightnessAndContrastCommand.Execute(null);
            }
        }
    }

First of all, I agree to Silvermind that it's better to put it in different sliders. But to answer your question, yes, what you're asking for is possible. You only want a single slider for two properties. The best way to do that is to do the logic in the view model by creating a third property that is responsible for changing the brightness, contrast. Let me call this property Value:

public int Value
{
    get
    {
        return _value; 
    }
    set
    {
        if (_value != value)
        {
            Set(() => Value, ref _value, value);
            ApplyChanges(_value);
        }                
    }
}

Every time the Value changes, it calls the method ApplyChanges, this will update your brightness or your Contrast depending on which control is selected.

void ApplyChanges(int value)
{       
    if(_selectedControl.Equals("brightness") && this.Brightness != value)
        this.Brigtness = value; 
    else if(_selectedControl.Equals("contrast") && this.Contrast != value)
        this.Contras = value; 
}

You said that the user will select a control that they like to use. So the selected control itself is another property that we need to keep track. You need to know in your view model which control is selected so you know which one (Brightness/contrast) should you update whenever the Value changes. In my example, to make it simple, I'll just use a string, this will tell the view model which one is selected.

public string SelectedControl
{
    get {  return _selectedControl;}
    set
    {
        if (_selectedControl != value)
        {
            Set(() => Contrast, ref _selectedControl, value);
            if(_selectedControl.Equals("brightness"))
                this.Value = this.Brightness;
            else if(_selectedControl.Equals("contrast"))
                this.Value = this.Contrast;
        }
    }
}

Everytime the selected control changes, if a user choose another control, we will update the Value property and pass the value of the currently selected control. When the user set the contrast to 3 and then set the brightness to 20 and then select the contrast again, the slider value should be back to 3 or the value of the contras. Every time the selected control changes, the value in the slider also updates.

And lastly you need to bind the property Value to the Slider's value.

I would use multiple Sliders, but create a separate Style for them that contains all the shared properties. That could reduce your code and make it easier to read/maintain.

<Style x:Key="MySliderStyle" TargetType="{x:Type Slider}">
    <Setter Property="IsSelectionRangeEnabled" Value="True" />
    <Setter Property="SelectionStart" Value="0" />
    <Setter Property="SelectionEnd" Value="150" />
    <Setter Property="Orientation" Value="Vertical" />
    <Setter Property="Minimum" Value="0" />
    <Setter Property="Maximum" Value="200" />
</Style>

<Slider Style="{DynamicResource MySliderStyle}" Grid.Row="0" Grid.Column="1" 
        Value="{Binding Brightness}" Visibility="{Binding IsBrightnessAndContrastEnabled, Converter={StaticResource VisibilityConverter}}">

If you really wanted to use the same slider though, you could dynamically change the Style assigned to the Slider control, and have the different Styles define what the Binding and Visibility values should be.

<Style x:Key="BrightnessSlider" TargetType="{x:Type Slider}" BasedOn="{DynamicResource MySliderStyle}">
    <Setter Property="Value" Value="{Binding Brightness}" />
    <Setter Property="Visibility" Value="{Binding IsBrightnessAndContrastEnabled, Converter={StaticResource VisibilityConverter}}" />
</Style>

<Slider x:Name="MySingleSlider" Grid.Row="0" Grid.Column="1">

And somehow in the code behind or whatever you use when switching what the slider is for :

MySingleSlider.Style = this.FindResource("BrightnessSlider") as Style;

You could also combine the two approaches and create styles as defined in #2 but use separate Sliders in your XAML as in #1. Then your XAML would be even simpler and you could customize the properties for each slider in their individual styles.

<Slider Style="{DynamicResource BrightnessSlider}" Grid.Row="0" Grid.Column="1">

(You could also put the Grid.Row and Grid.Column properties in the <Style> , but typically they're associated with however you're laying out your controls, so I prefer to keep those properties on the Control)

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