WPF:如何为垂直滑块设置动态数字范围? [英] WPF: How to set a dynamic range of numbers for vertical slider?

查看:21
本文介绍了WPF:如何为垂直滑块设置动态数字范围?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm currently working with an WPF MVVM project which has a user control used by several views but with a different range of values. Here is an example of what i need.

如您所见,控件必须根据我需要在滑块中显示的值以不同的行为做出响应(无论数字如何,这只是一个示例).问题之一是该项目是使用 MVVM 设计模式开发的,因此代码背后"不应该是一个好的选择(但如果它解决了问题,对我来说很好),所以我认为它可能是一个在 XAML 中更难做到这一点.

As you can see, the control has to respond with a different behavior depending on the values which i need to show in the slidder (no matter the numbers, this is just an example). One of the problems is that the project is developed using the MVVM design pattern, so the 'code behind' should not be a good option (but if it solves the problem, it is fine for me), so i think it might be a bit harder to do it in the XAML.

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

The pics which I have shown before was done it in static way by creating a grid just beside the slider with a couple of textblocks, but is impossible to hold this solution because i have to create a new one anytime I need it. I thought to start a solution by using a StackPanel or DockPanel with a set height... but if you think a little this is not a good option when you want to show two values because you need to specify the vertical align for each of this values, and this doesn't sounds good.

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

The only way I think is to make an override or something which allows the slider to show the Ticks based on the height of the slider... is there a way to do something like this?

我只是写了几行代码,但没有什么相关的,因为我不知道如何解决这个任务.我不需要代码,我需要想法.

I just wrote some lines of code, but nothing relevant because I don't know how to solve this task. I don't need code, I need ideas.

推荐答案

我们一起工作,所以我会将我们找到的解决方案留给这个问题,以防其他人感兴趣.

We work together so i will leave the solution we have found to this problem in case anyone else is interested.

首先我们创建了 2 个类.

First we have created 2 classes.

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 类:

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)));
            }
        }
    }

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

Then we have replaced the tickbar on control template of the vertical slider like the following example:

带有标签的垂直滑块

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

but also adding the 2 new values of dependency properties:

 <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 中,我们有一些类似这样的代码:

Finally on the xaml of the user control we have some code like this one:

<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>

希望这个方法可以帮助其他人.

Hope this approch can help anyone else.

这篇关于WPF:如何为垂直滑块设置动态数字范围?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆