對於Button的Command的綁定可以通過實現ICommand接口來進行,但是Slider並沒有Command屬性。
另外如果要實現MVVM模式的話,需要將一些Method和Slider的Event進行綁定,如何進行呢?
(對於UIElement的一些Event進行綁定一定有一些通用的方法,目前還沒有深入研究。)
首先,Slider Value的綁定是很簡單的, 綁定Slider的Value屬性即可。
(1)ViewModel
public class SliderViewModel : ViewModelBase { private string selectedValue; public SliderViewModel() { } public string SelectedValue { get { return this.selectedValue; } set { if (this.selectedValue != value) { this.selectedValue = value; base.OnPropertyChanged("SelectedValue"); } } } }
(2) View, 設定 DataContext 為ViewModel, 綁定SelectValue到 Slider的Value 和TextBlock的Text屬性上。
這樣當拖動Slider時,Slider的值會傳給SelectedValue, 然后SelectValue會傳給TexBlock上。
x:Class="WpfApplication2.View.SliderView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:vm="clr-namespace:WpfApplication2.ViewModel" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <UserControl.DataContext> <vm:SliderViewModel /> </UserControl.DataContext> <Grid> <Slider HorizontalAlignment="Left" Margin="28,102,0,0" VerticalAlignment="Top" Width="158" Minimum="0" Maximum="100" Value="{Binding SelectedValue}"/> <TextBlock HorizontalAlignment="Left" Margin="203,102,0,0" TextWrapping="Wrap" Text="{Binding SelectedValue}" VerticalAlignment="Top" /> </Grid> </UserControl>
效果如下:
如果不想顯示double值,可以設定Slider的屬性。
TickFrequency="1"
IsSnapToTickEnabled="True"
TickPlacement="None" />
其次, 當用鼠標或者鍵盤移動滑塊結束的時候,需要進行一些處理。如果不用MVVM的方式的話,可以在Slider的Event里面增加處理。
用MVVM的話,就稍微麻煩一些。
(1)下載或者復制C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\.NETFramework\v4.0\Libraries\System.Windows.Interactivity.dll
在工程中Reference 這個dll,命名空間里面增加:using System.Windows.Interactivity
(2)新寫個SliderValueChangedBehavior 繼承Behavior<Slider>
/// <summary> /// Helps find the user-selected value of a slider only when the keyboard/mouse gesture has ended. /// </summary> public class SliderValueChangedBehavior : Behavior<Slider> { /// <summary> /// Keys down. /// </summary> private int keysDown; /// <summary> /// Indicate whether to capture the value on latest key up. /// </summary> private bool applyKeyUpValue; #region Dependency property Value /// <summary> /// DataBindable value. /// </summary> public double Value { get { return (double)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( "Value", typeof(double), typeof(SliderValueChangedBehavior), new PropertyMetadata(default(double), OnValuePropertyChanged)); #endregion #region Dependency property Value /// <summary> /// DataBindable Command /// </summary> public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } } public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( "Command", typeof(ICommand), typeof(SliderValueChangedBehavior), new PropertyMetadata(null)); #endregion /// <summary> /// On behavior attached. /// </summary> protected override void OnAttached() { this.AssociatedObject.KeyUp += this.OnKeyUp; this.AssociatedObject.KeyDown += this.OnKeyDown; this.AssociatedObject.ValueChanged += this.OnValueChanged; base.OnAttached(); } /// <summary> /// On behavior detaching. /// </summary> protected override void OnDetaching() { base.OnDetaching(); this.AssociatedObject.KeyUp -= this.OnKeyUp; this.AssociatedObject.KeyDown -= this.OnKeyDown; this.AssociatedObject.ValueChanged -= this.OnValueChanged; } /// <summary> /// On Value dependency property change. /// </summary> private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var me = (SliderValueChangedBehavior)d; if (me.AssociatedObject != null) me.Value = (double)e.NewValue; } /// <summary> /// Occurs when the slider's value change. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void OnValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { if (Mouse.Captured != null) { this.AssociatedObject.LostMouseCapture += this.OnLostMouseCapture; } else if (this.keysDown != 0) { this.applyKeyUpValue = true; } else { this.ApplyValue(); } } private void OnLostMouseCapture(object sender, MouseEventArgs e) { this.AssociatedObject.LostMouseCapture -= this.OnLostMouseCapture; this.ApplyValue(); } private void OnKeyUp(object sender, KeyEventArgs e) { if (this.keysDown-- != 0) { this.ApplyValue(); } } private void OnKeyDown(object sender, KeyEventArgs e) { this.keysDown++; } /// <summary> /// Applies the current value in the Value dependency property and raises the command. /// </summary> private void ApplyValue() { this.Value = this.AssociatedObject.Value; if (this.Command != null) this.Command.Execute(this.Value); } }
(3) 在View中為Slider的行為添加Command
<i:Interaction.Behaviors> <helper:SliderValueChangedBehavior Command="{Binding ValueChangedCommand}" /> </i:Interaction.Behaviors>
(4)在ViewModel中實現當Slider值個改變的時候進行一些處理。
public ICommand ValueChangedCommand { get { if (this.valueChangedCommmand == null) { this.valueChangedCommmand = new RelayCommand( param => this.PopValue(), null); } return this.valueChangedCommmand; } } private void PopValue() { MessageBox.Show(String.Format("Selected value is {0}", this.selectedValue)); }
最后,進行調試,發現ValueChangedCommand當每次Silder值變更的時候都會被執行。
那么如何實現最后一次值變更時,才執行Command呢?