gpt4 book ai didi

c# - Slider.Value 在不应该调整最小值时发生变化

转载 作者:行者123 更新时间:2023-12-02 11:03:16 29 4
gpt4 key购买 nike

简而言之:
在某些情况下,设置 Slider.Minimum 将调整 Slider.Value,尽管当前值大于新的最小值。

代码: (应该是可复制的)
主窗口.xaml:

<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<Slider Name="MySlider" DockPanel.Dock="Top" AutoToolTipPlacement="BottomRight" />
<Button Name="MyButton1" DockPanel.Dock="Top" Content="shrink borders"/>
<Button Name="MyButton2" DockPanel.Dock="Top" VerticalAlignment="Top" Content="grow borders"/>
</DockPanel>
</Window>

主窗口.xaml.cs:
using System.Windows;
using System.Windows.Controls;

namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

MySlider.ValueChanged += (sender, e) =>
{
System.Diagnostics.Debug.WriteLine("Value changed: " + e.NewValue);
};

System.ComponentModel.DependencyPropertyDescriptor.FromProperty(Slider.MinimumProperty, typeof(Slider)).AddValueChanged(MySlider, delegate
{
System.Diagnostics.Debug.WriteLine("Minimum changed: " + MySlider.Minimum);
});

System.ComponentModel.DependencyPropertyDescriptor.FromProperty(Slider.MaximumProperty, typeof(Slider)).AddValueChanged(MySlider, delegate
{
System.Diagnostics.Debug.WriteLine("Maximum changed: " + MySlider.Maximum);
});

MySlider.Value = 1;

MySlider.Minimum = 0.5;
MySlider.Maximum = 20;

MyButton1.Click += (sender, e) =>
{
MySlider.Minimum = 1.6;
MySlider.Maximum = 8;
};

MyButton2.Click += (sender, e) =>
{
MySlider.Minimum = 0.5;
MySlider.Maximum = 20;
};
}
}
}

重现步骤:
1. 在 Debug模式下运行。
2. 将滑块移动到最右侧。
3. 按“缩小边框”按钮。
4. 按“增加边框”按钮。

预期输出:
Value changed: 1
Minimum changed: 0,5
Maximum changed: 20
//Multiple times "Value changed"
Value changed: 20
Minimum changed: 1,6
Value changed: 8
Maximum changed: 8
Minimum changed: 0,5
Maximum changed: 20

滑块停留在 8。

实际输出:
Value changed: 1
Minimum changed: 0,5
Maximum changed: 20
//Multiple times "Value changed"
Value changed: 20
Minimum changed: 1,6
Value changed: 8
Maximum changed: 8
Value changed: 1
Minimum changed: 0,5
Maximum changed: 20

(请注意附加的“值已更改:1”)
滑块跳到 1。

旁注:
将 Slider.Value OneWayToSource(或 TwoWay)绑定(bind)到 double 属性,修复了该问题。

问题:
为什么会这样?

理论:
我很确定它与 Value Coercion有关.似乎发生了以下情况:
1. 将 Value 设置为 1 编程设置 Value 的“基值”。它介于最小值和最大值的默认值之间,因此“有效值”完全相同。
2.设置最小值和最大值不会改变任何东西,因为值仍然在它们之间。
3. 手动将滑块向右拉显然会改变“有效值”,但由于某种奇怪的原因而不是“基值”。
4.再次增加边界,调用强制回调,它意识到(错误的)“基值”在新的最小值和最大值之间,并将“有效值”改回它。

假设这确实是正在发生的事情,将我们引向以下问题:
为什么手动拉动滑块 (3.) 不会影响“基值”?

最佳答案

我不确定用例是什么,但是如果您使用的是 MVVM 并且一切都被绑定(bind),这个问题可能可以避免。如果这就是您正在做的事情,而这只是您重现问题的另一种方式,那就太好了。

看看 Slider source code .我无法查明问题,但我更好地理解了正在使用的内部值。

添加 2 个按钮,并且只更改所有按钮的事件处理程序中的最小值或最大值:

MyButton1.Click += (sender, e) =>
{
MySlider.Minimum = 1.6;
};

MyButton2.Click += (sender, e) =>
{
MySlider.Minimum = 0.5;
};

MyButton3.Click += (sender, e) =>
{
MySlider.Maximum = 20;
};

MyButton4.Click += (sender, e) =>
{
MySlider.Maximum = 8;
};

启动时,点击 MyButton1MyButton2 :
Value changed: 1.6
Minimum changed: 1.6
Value changed: 1
Minimum changed: 0.5
Value changed: 1.6
Minimum changed: 1.6
Value changed: 1
Minimum changed: 0.5

您可以看到,在内部,它存储原始起始值并在范围能够显示时将其恢复,并将其设置回原来的值。如果您在启动时仅更改最大值(不移动滑块), Value属性未更改,因为 Value在当前范围内:
Maximum changed: 8
Maximum changed: 20
Maximum changed: 8
Maximum changed: 20

但是,当您将滑块条最大值更改为 20 时,则更改 Maximum = 8Minimum = 1.6 , Minimum现在超出​​范围(内部) Value (1) 并使用 Maximum它的值(value)是 Value .当你再次种植它时,你设置 Minimum = 0.5Maximum = 20 ,并且由于内部值 = 1 并且介于 0.5 和 20 之间,因此它设置了 Value回到 1。

我找到了一种解决方法,那就是每次更改范围时都重置内部值。要重置,您只需设置 Slider.Value再次。如果您在更改 Maximum 后执行此操作和 Minimum如果旧值不在新范围内,它将保留该值。因此,以您的初始实现为例:
MyButton1.Click += (sender, e) =>
{
MySlider.Minimum = 1.6;
MySlider.Maximum = 8;
MySlider.Value = MySlider.Value;
};

MyButton2.Click += (sender, e) =>
{
MySlider.Minimum = 0.5;
MySlider.Maximum = 20;
MySlider.Value = MySlider.Value;
};

输出(符合您的预期):
Value changed: 1
Minimum changed: 0.5
Maximum changed: 20
//Multiple times "Value changed"
Value changed: 20
Minimum changed: 1.6
Value changed: 8
Maximum changed: 8
Minimum changed: 0.5
Maximum changed: 20

编辑

您发布的有关值(value)强制的链接非常有帮助。我不确定您的问题是否会被视为第二个问题,但我相信我找到了答案。

当您使用 Slider (技术上是 ThumbTrack ),意识到 Thumb左右滑动绑定(bind)到 Slider.Value通过 Slider.UpdateValue 被调用。现在这个问题是 SetCurrentValueInternal不是开源的 :( 我们可以得出的结论是神秘函数不会强制 ValueProperty ,而是仅设置基本(“期望”)值。尝试:
private void MyButton1_Click(object sender, RoutedEventArgs e)
{
MySlider.Minimum = 1.6;
MySlider.Maximum = 8;
MySlider.CoerceValue(Slider.ValueProperty); //Set breakpoint, watch MySlider.Value before and after breakpoint.
}

执行上述操作您会看到,即使 Value将从 20 下降到 8,当它下降到 8 时您实际上强制 ValueProperty 的第二个,然后该值将更改为 1.6 .事实上,这就是当您扩大范围时会发生的情况。设置 Max 或 Min 后,您将看到 Value 更改,因为它再次强制 value 属性。尝试翻转 Max 和 Min:
private void MyButton2_Click(object sender, RoutedEventArgs e)
{
MySlider.Maximum = 20; //Will change Value to 1.6 after executing
MySlider.Minimum = 0.5; //Will change Value to 1 after executing
}

尽管如此,这还是让你思考,它怎么能记住在可能的情况下回到 1,是否有一个有效的、基数和初始值?我不知道。

事实上试试这个。
  • 开始申请
  • 将拇指一直向右移动(值 = 20)
  • 缩小边框(值 = 8)
  • 将拇指向左移动,然后一直向右移动(值 = 8)
  • 然后长边框

  • 在第 5 步之后,您将观察到 Value 仍然等于 8。这就是我发现它与那个神秘函数有关的方式。

    注意:我的大脑又死了,所以如果这不是很清楚,我很抱歉,我必须回来编辑它。

    编辑 2

    一方面,两者都是 SetCurrentValueInteralSetValue双方调用 SetValueCommon .区别是 SetCurrentValueInternal由于强制标志设置为 true,因此使用基值重新评估当前值。 (保持最小值/最大值范围内的值), ref .

    通过我的挖掘,我发现 SetCurrentValueSetValue有两个完全不同的结果,即:指定强制转换(在绑定(bind)属性为值类型的情况下, IsInternal 似乎未使用)。

    我的证明是 documentation指出:

    "The SetCurrentValue method is another way to set a property, but it is not in the order of precedence. Instead, SetCurrentValue enables you to change the value of a property without overwriting the source of a previous value. You can use SetCurrentValue any time that you want to set a value without giving that value the precedence of a local value..."



    话虽如此,移动 ThumbSlider不影响基值,因为它正在调用 SetCurrentValueInternal .

    此外,更改 Value手动更改基值,因为它调用 SetValue . ValueProperty依赖属性定义了如何使用 CoerceValueCallback 进行强制。如最后一段 here 所述.更详细地了解 Slider.Value 中正在发生的事情,

    Coercion interacts with the base value in such a way that the constraints on coercion are applied as those constraints exist at the time, but the base value is still retained. Therefore, if constraints in coercion are later lifted, the coercion will return the closest value possible to that base value, and potentially the coercion influence on a property will cease as soon as all constraints are lifted.



    当然我进一步阅读, Dependency Property Callbacks and Validation - Advanced Coercion and Callback Scenarios并发现了这个:

    For instance, in the Min/Max/Current scenario, you could choose to have Minimum and Maximum be user settable. If so, you might need to coerce that Maximum is always greater than Minimum and vice versa. But if that coercion is active, and Maximum coerces to Minimum, it leaves Current in an unsettable state, because it is dependent on both and is constrained to the range between the values, which is zero. Then, if Maximum or Minimum are adjusted, Current will seem to "follow" one of the values, because the desired value of Current is still stored and is attempting to reach the desired value as the constraints are loosened.



    总之,我认为这是在 Slider 中设计的因为它的编码方式是 Value必须始终介于 Minimum 之间和 Maximum . Value将关注 Maximum属性,当解除约束(当前值在基值范围内)时,value 属性将返回其原始值。

    最后,IMO WPF 以这种方式设计了滑块,因为 WPF 与数据绑定(bind)密切相关。我认为他们的设计假设开发人员将充分利用数据绑定(bind)并实现逻辑以防止使用无效值。

    关于c# - Slider.Value 在不应该调整最小值时发生变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32053283/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com