スライダーとテキストボックスでのデータバインディングで発生している問題を解決する方法を見つけるのに最も苦労しています。
設定:スライダーの現在の値がテキストボックス内に表示されます。ユーザーがスライダーをドラッグすると、値がテキストボックス内に反映されます。ユーザーは、スライダーをドラッグして選択した値まで離すか、スライダートラックの任意の場所をクリックして値を設定するか、texboxに手動で値を入力するかを選択できます。最後のケースでは、テキストボックスに入力された値によってスライダーの位置が更新されます。
texboxはdatacontextプロパティに双方向でバインドされていますが、スライダーは同じプロパティに一方向でバインドされています。ユーザーがスライダートラッカーをスライドまたはクリックすると、スライダーのdragcompletedイベントを使用して、変更をデータコンテキストに通知します。一方、ユーザーがトラッカーをクリックすると、スライダーのOnValueChangedイベントを使用してデータコンテキストに通知します(フラグを使用して、OnValueChangedがスライダーの移動によってトリガーされないようにします)
問題:スライダー値をバインディング値で初期化してもOnValueChangedイベントが発生するため、値が実際にユーザーからのものかバインディングからのものかがわかりません。
スライダーのユーザー更新とバインド更新を確実に区別できるように、バインドを行うための代替方法を提案していただけますか?やめろ!
更新申し訳ありませんが、以下の回答が示すように、スライダーとテキストボックスの両方を直接バインドしない理由を2つの方法で説明するのを忘れました。データコンテキスト値の更新は、バックエンドサーバーへの呼び出しをトリガーし、データベースからデータを取得することになっています。問題は、ユーザーがスライダーをドラッグすると、常に更新が発生することです。DoWhateverメソッドを呼び出すために実際のonValueChangedイベントのみに依存することで、問題を回避します。それがもう少し明確になることを願っています。これを省略してすみません...
以下のサンプルを簡単にまとめて、試してみてください。
xaml:
<Window x:Class="SliderIssue.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">
<Grid HorizontalAlignment="Center"
VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Slider Name="slider" VerticalAlignment="Top"
ValueChanged="slider_ValueChanged"
Thumb.DragStarted="slider_DragStarted"
Thumb.DragCompleted="slider_DragCompleted"
Value="{Binding Count}"
Width="200"
Minimum="0"
Maximum="100"/>
<TextBox VerticalAlignment="Top"
HorizontalAlignment="Left"
Grid.Column="1"
Width="100"
Text="{Binding Count,Mode=TwoWay,UpdateSourceTrigger=LostFocus}"
Height="25"/>
</Grid>
背後にあるコード:
using System.Windows;
namespace SliderIssue
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private bool _dragStarted;
public MainWindow()
{
InitializeComponent();
var item = new Item();
DataContext = item;
}
private void slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (!_dragStarted)
{
var item = (Item)DataContext;
item.DoWhatever(e.NewValue);
}
}
private void slider_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{
_dragStarted = true;
}
private void slider_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
{
_dragStarted = false;
var item = (Item) DataContext;
item.DoWhatever(slider.Value);
}
}
}
単純なデータクラス:
using System.ComponentModel;
namespace SliderIssue
{
public class Item : INotifyPropertyChanged
{
private int _count = 50;
public int Count
{
get { return _count; }
set
{
if (_count != value)
{
_count = value;
DoWhatever(_count);
OnPropertyChanged("Count");
}
}
}
public void DoWhatever(double value)
{
//do something with value
//and blablabla
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}