我有一个滑块,它使用慢速getter和setter绑定到一个属性。由于UI需要响应,因此绑定具有属性IsAsync
。但是当我拖动滑块时,它会在光标和0之间跳转(默认为FallbackValue
)。
有人知道如何防止此行为,如何禁用FallbackValue
?
XAML:
<Slider>
<Slider.Value>
<Binding Path="Value" IsAsync="True"/>
<!-- For testing, best plan till now
<PriorityBinding>
<Binding Path="Value" IsAsync="True"/>
<Binding Path="CurrentValue"/>
</PriorityBinding>
-->
</Slider.Value>
</Slider>
代码背后:
public int Value
{
get
{
//if (setterCount > 0) // For testing, best plan till now
//{
// return CurrentValue;
//}
Thread.Sleep(100); // Just for simulating slow functionality
return myValue;
}
set
{
//++setterCount; // For testing, best plan till now
//CurrentValue = value;
Thread.Sleep(200); // Just for simulating slow functionality
myValue = value;
//--setterCount;
OnPropertyChanged("Value");
}
}
答案 0 :(得分:1)
不要在财产内部调用阻止操作,但这并不意味着这一点。
正常绑定值并在命令中查询/验证它的输入。
<i:Interaction.Triggers>
<i:EventTrigger EventName="ValueChanged">
<cmd:EventToCommand Command="{Binding UpdateSomethingCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
在命令中执行async
public ICommand UpdateSomethingCommand { get; } = new RelayCommand(UpdateSomething);
private async void UpdateSomething()
{
await SomeLengthlyCallOrValidation(this.SliderValue);
}
答案 1 :(得分:1)
我不知道这个解决方案是否可以被视为“纯MVVM”,但让我们提出它并看看它是否适合你。 首先,我们定义一个Slider并订阅Thumb.DragCompleted事件。我们还将UpdateSourceTrigger设置为显式:
<Slider Maximum="100" Minimum="0" Width="300" x:Name="slid" Thumb.DragCompleted="MySlider_DragCompleted" >
<Slider.Value>
<Binding Path="Value" UpdateSourceTrigger="Explicit"/>
</Slider.Value>
</Slider>
现在在代码隐藏中的事件处理程序中,我们这样做:
private void MySlider_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
{
BindingExpression be = slid.GetBindingExpression(Slider.ValueProperty);
be.UpdateSource();
}
总结一下,我们在这里做的只是在“滑动”过程完成时才进行绑定(获取/设置滑块值)。
答案 2 :(得分:0)
没有必要使getter异步,只需存储(缓存)最后一个值。 您可以正常绑定到属性并自己实现异步更新:
视图:
<Slider Value="{Binding Value, Delay=100}" Maximum="..." />
视图模型:
Task _task = Task.Run(() => { }); // Task.CompletedTask in 4.6
volatile int _id;
double _value;
public double Value
{
get { return _value; }
set
{
_value = value;
OnPropertyChanged();
// task
var id = ++_id; // capture id
_task = _task.ContinueWith(o =>
{
if (_id == id)
{
Thread.Sleep(1000); // simulate work
// this is optional if value stays the same
if (_id == id)
{
_value = value + 10; // simulate different value
Dispatcher.InvokeAsync(() => OnPropertyChanged(nameof(Value)));
}
}
});
}
}
想法:记录滑块值更改并仅执行最后一个。
通过使用ContinueWith
链接任务来完成录制。首先,您已完成任务,Value
的每次更改都将创建一个新任务。
我不知道是否有办法检查当前任务何时继续,因此_id
用于此目的。当_id == id
任务是链中的最后一个任务时(否则任务不执行任务,因为有更多实际更新)。
第二个if
用于检查 工作后是否有更多任务并阻止值更改返回(当前效果)。如果您的工作可以返回与设置的值不同的值,则需要此通知。否则完全删除第二个if
(不需要)。
注意Delay
在绑定中,它会减少任务数量(没有它一个滑块的移动可能产生几十个任务)。