WPF:如何为垂直滑块设置动态数字范围?

时间:2013-12-02 13:51:24

标签: wpf slider

我目前正在使用WPF MVVM项目,该项目具有由多个视图使用的用户控件,但具有不同的值范围。 这是我需要的一个例子。

values enter image description here enter image description here

正如您所看到的,控件必须以不同的行为进行响应,具体取决于我需要在滑动器中显示的值(无论数字,这只是一个示例)。 其中一个问题是该项目是使用MVVM设计模式开发的,因此“代码隐藏”不应该是一个不错的选择(但如果它解决了问题,那对我来说很好),所以我认为它可能是一个在XAML中更难做到。

我之前展示过的图片是通过在滑块旁边创建一个带有几个文本块的网格以静态方式完成的,但是不可能保留这个解决方案,因为我必须在需要的时候创建一个新的。 我想通过使用具有设定高度的StackPanel或DockPanel来开始一个解决方案...但是如果你想一点,当你想显示两个值时,这不是一个好的选择,因为你需要为每个值指定垂直对齐价值,这听起来不太好。

我认为唯一的方法是进行覆盖或允许滑块根据滑块高度显示Ticks的东西......有没有办法做这样的事情?

我刚写了几行代码,但没有任何相关性,因为我不知道如何解决这个问题。我不需要代码,我需要创意。

1 个答案:

答案 0 :(得分:1)

我们一起工作,所以我会留下我们发现的解决方案,以防其他人感兴趣。

首先我们创建了2个类。

1)一个继承自SLIDER的类,具有中间范围的2个依赖属性(图像中的绿色数字),如下所示:

class NumberedSlider : System.Windows.Controls.Slider
    {
        public static readonly DependencyProperty RangeMinProperty = DependencyProperty.Register(
                 "RangeMinSlider", typeof(int), typeof(NumberedTickBar), new FrameworkPropertyMetadata(0));

        public int RangeMin
        {
            get { return (int)base.GetValue(RangeMinProperty); }
            set { base.SetValue(RangeMinProperty, value); }
        }

        public static readonly DependencyProperty RangeMaxProperty = DependencyProperty.Register(
                  "RangeMaxSlider", typeof(int), typeof(NumberedTickBar), new FrameworkPropertyMetadata(0));

        public int RangeMax
        {
            get { return (int)base.GetValue(RangeMaxProperty); }
            set { base.SetValue(RangeMaxProperty, value); }
        }
    }

2)滑块TickBar的一个类,它将呈现de数字:

public class NumberedTickBar : TickBar
    {
        public static readonly DependencyProperty RangeMinProperty = DependencyProperty.Register(
            "RangeMin", typeof (int), typeof (NumberedTickBar), new FrameworkPropertyMetadata(0));

        public int RangeMin
        {
            get { return (int) base.GetValue(RangeMinProperty); }
            set { base.SetValue(RangeMinProperty, value); }
        }

        public static readonly DependencyProperty RangeMaxProperty = DependencyProperty.Register(
            "RangeMax", typeof (int), typeof (NumberedTickBar), new FrameworkPropertyMetadata(0));

        public int RangeMax
        {
            get { return (int) base.GetValue(RangeMaxProperty); }
            set { base.SetValue(RangeMaxProperty, value); }
        }

        protected override void OnRender(DrawingContext dc)
        {
            Size size = new Size(base.ActualWidth, base.ActualHeight);

            int tickCount;

            if ((this.Maximum - this.Minimum)%this.TickFrequency == 0)
                tickCount = (int) ((this.Maximum - this.Minimum)/this.TickFrequency);
            else
                tickCount = (int) ((this.Maximum - this.Minimum)/this.TickFrequency) + 1;

            double tickFrequencySize = (size.Height*this.TickFrequency/(this.Maximum - this.Minimum));

            // Draw each tick text
            for (int i = 0; i <= tickCount; i++)
            {
                int value = Convert.ToInt32(this.Minimum + this.TickFrequency*i);

                string text = Convert.ToString(value, 10);
                FormattedText formattedText;
                if (value >= this.RangeMin && value <= this.RangeMax)
                    formattedText = new FormattedText(text, CultureInfo.GetCultureInfo("en-us"),
                                                      FlowDirection.LeftToRight, new Typeface("Arial Rounded MT Bold"), 16,
                                                      Brushes.Green);
                else
                    formattedText = new FormattedText(text, CultureInfo.GetCultureInfo("en-us"),
                                                      FlowDirection.LeftToRight, new Typeface("Arial Rounded MT Bold"), 16,
                                                      Brushes.DarkBlue);

                dc.DrawText(formattedText, new Point(30, (tickFrequencySize*(tickCount - i)-6)));
            }
        }
    }

然后我们替换了垂直滑块控件模板上的标记栏,如下例所示:

Vertical slider with labels on the ticker

但还添加了2个依赖属性的新值:

 <common:NumberedTickBar   Margin="0,0,0,10" x:Name="TopTick" 
                                      SnapsToDevicePixels="True" Placement="Left" 
                                      Fill="{StaticResource GlyphBrush}" Width="4" 
                                      RangeMax="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RangeMax}"
                                      RangeMin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RangeMin}"/>

最后在用户控件的xaml上,我们有一些像这样的代码:

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="50*"/>
            <ColumnDefinition Width="50*"/>
        </Grid.ColumnDefinitions>
        <Grid>
            <common:NumberedSlider x:Name="SliderValue" MinHeight="180" Margin="5 15 5 15" Orientation="Vertical" 
                                   Maximum="89" 
                                   Minimum="77" 
                                   Value="{Binding BarValue, Mode=TwoWay}"  
                                   TickFrequency="1" 
                                   IsSnapToTickEnabled="True" 
                                   RangeMin="82" 
                                   RangeMax="85"
                                   IsEnabled="{Binding SliderEnabled}"/>
        </Grid>
        <Grid Grid.Column="1">
            <ProgressBar Orientation="Vertical" Width="70" 
                         Minimum="{Binding ElementName=SliderValue,Path=Minimum}" 
                         Maximum="{Binding ElementName=SliderValue,Path=Maximum}" 
                         Value="{Binding ElementName=SliderValue, Path=Value}" Margin="0 14" Background="Gray" MinHeight="200"
                         Foreground="{Binding ColorBar, Converter= {StaticResource setSteelPointLevelConverter}}"                          />
        </Grid>
    </Grid>

希望这个approch可以帮助其他任何人。