Ползунок.Значение изменяется при настройке Minimum, когда оно не должно
короче:
При определенных обстоятельствах установка слайдера.Минимум отрегулирует слайдер.Значение хотя текущее значение больше, чем новый минимум.
код: (должно быть повторимо)
файл MainWindow.язык 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>
файл MainWindow.код 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. Запуск в режиме отладки.
2. Переместите ползунок вправо.
3. Нажмите кнопку "shrink borders".
4. Нажмите кнопку" grow borders".
Ожидаемый Результат:
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.
Sidenote:
Бегунок Привязки.Значение OneWayToSource (или TwoWay) для свойства double, исправляет вопрос.
вопрос:
Почему это происходит?
теория:
Я уверен, что это как-то связано с Значение Принуждения. Кажется, происходит следующее:
1. Установка значения в 1 программно устанавливает "базовое значение" значения. Он находится между значениями по умолчанию для минимального и максимального, поэтому "эффективное значение" точно так же.
2. Установка минимума и максимума ничего не меняет, потому что Ценность все еще между ними.
3. Вручную потянув ползунок вправо, по-видимому, изменяет "эффективное значение", но по какой-то странной причине не"базовое значение".
4. Снова увеличивая границы, вызывает обратный вызов принуждения, который понимает, что (неправильное) "базовое значение" находится между новым минимумом и максимумом и изменяет "эффективное значение" обратно на него.
предполагая, что это действительно то, что происходит, приводит нас к следующему вопросу:
Почему вручную потянув ползунок (3.) не влияет на "базовое значение"?
1 ответов
я не уверен, что такое вариант использования, но этой проблемы можно было бы избежать, если бы вы использовали MVVM, и все было связано. Если это то, что вы делаете, и это просто еще один способ воспроизведения проблемы, хорошая находка.
посмотри Slider
исходный код. Я не мог точно определить проблему, но у меня есть лучшее понимание того, что используется внутреннее значение.
добавить 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;
};
при запуске, нажмите кнопку MyButton1
и MyButton2
:
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 = 8
и Minimum = 1.6
, the Minimum
теперь вне диапазона от (внутреннего)Value
(1) и использует Maximum
значение для него Value
. Когда вы вырастите его снова, вы установите Minimum = 0.5
и Maximum = 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
редактировать
ссылка, которую вы опубликовали о принуждении стоимости, очень полезна. Я не уверен, что ваш вопрос будет считаться вторым вопросом, но я считаю, что нашел ответ.
при использовании Slider
(технически Thumb
С Track
), что Thumb
скольжение вокруг связано с 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, второй вы фактически принуждаете ValueProperty, когда он падает до 8, значение затем изменится на 1.6
. На самом деле, это то, что происходит, когда вы увеличиваете диапазон. После установки Max или Min вы увидите изменение значения, так как оно снова принуждает свойство 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 вы увидите, что значение по-прежнему равно 8. Вот как я узнал, что это как-то связано с этой тайной. функция.
Примечание: мой мозг снова мертв, поэтому, если это не ясно, Я извиняюсь, мне придется вернуться и отредактировать его.
Изменить 2
например, как SetCurrentValueInteral
и SetValue
как позвонить SetValueCommon
. Разница в SetCurrentValueInternal
повторно оценивает текущее значение с базовым значением, так как флаг принуждения установлен в true. (сохраняет значение в пределах Min / Max),ref.
через мои раскопки, я нашел, что SetCurrentValue
и SetValue
имеют два совершенно разных результата, а именно: указание принуждения (IsInternal
кажется неиспользуемым в случае, когда свойство bound имеет тип value).
доказательство документация о:
"метод SetCurrentValue-это еще один способ задать свойство, но не в порядке приоритета. Вместо этого SetCurrentValue позволяет изменять значение свойства без перезаписи источника предыдущего значения. Вы можете использовать SetCurrentValue в любое время, когда вы хотите установить значение, не давая этому значению приоритет локального значения..."
С этим, как говорится, двигая Thumb
на Slider
не влияет на базовое значение, потому что он называет SetCurrentValueInternal
.
Value
вручную изменяет базовое значение, потому что оно вызывает SetValue
. The ValueProperty
свойство зависимостей определяет, как принудительно использовать CoerceValueCallback
как указано в последнем параграф здесь. Более подробно о том, что происходит в Slider.Value
,
принуждение взаимодействует с базовым значением таким образом, что ограничения на принуждение применяются, поскольку эти ограничения существуют в то время, но базовое значение все еще сохраняется. Поэтому, если ограничения в принуждении позже будут сняты, принуждение вернет максимально возможное значение к этому базовому значению, и потенциально влияние принуждения на свойство прекратится, как только все ограничения сняты.
конечно, я читаю дальше,обратные вызовы свойств зависимостей и проверка-расширенные сценарии принуждения и обратного вызова и
например, в сценарии Min/Max / Current вы можете выбрать минимальную и максимальную настройки пользователя. Если это так, вам может потребоваться принудить, что максимум всегда больше минимума и наоборот. Но если это принуждение активно, и максимум принуждает Минимум, он оставляет ток в неразрешимом состоянии, потому что он зависит от обоих и ограничен диапазоном между значениями, который равен нулю. Затем, если скорректировать максимум или минимум, ток будет "следовать" за одним из значений, потому что желаемое значение тока все еще сохраняется и пытается достичь желаемого значения по мере ослабления ограничений.
в заключение, я думаю, что это как-разработанные в Slider
потому что он закодирован таким образом, что Value
должно быть всегда между Minimum
и Maximum
. The Value
будет следовать Maximum
свойство, и при снятии ограничений (текущее значение находится в диапазоне базового значения) свойство value вернется к исходному значению.
наконец, IMO WPF разработал слайдер таким образом, потому что WPF идет рука об руку с привязкой данных. Я предполагаю, что они разработаны в предположении, что разработчики в полной мере воспользуются связыванием данных и реализуют логику запретить использование недопустимых значений.