У меня есть приложение WPF
, использующее LiveCharts
, где я строю LineGraph
с осью X, равной DateTime
. Моя конечная цель здесь - добиться «двустороннего» увеличения. То есть у меня есть два DateTimePicker
элемента управления (из WPF Toolkit ) в моем приложении, которые представляют минимальный и максимальный DateTime
отображаемой в данный момент области графика, и еслиЯ использую колесо прокрутки в области графика для увеличения / уменьшения масштаба, обновленный диапазон должен отражаться на указанных элементах управления, и (с этой частью я борюсь), наоборот, если я установил min / max на DateTimePicker
управления, график должен соответственно увеличиваться / уменьшаться.
Мой XAML
довольно прост:
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<lvc:CartesianChart Name="MyChart"
Series="{Binding SeriesCollection}"
Zoom="X">
<lvc:CartesianChart.AxisX>
<lvc:Axis LabelFormatter="{Binding Formatter}"
PreviewRangeChangedCommand="{Binding XRangeChangedCommand}"
MinValue="{Binding TimeStampMin, Mode=TwoWay}"
MaxValue="{Binding TimeStampMax, Mode=TwoWay}"/>
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center">
<xceed:DateTimePicker Margin="4" Width="160" Name="dtpMinX"
Format="Custom" FormatString="yyyy/MM/dd HH:mm:ss"
Value="{Binding TimeStampMin, Mode=TwoWay}"/>
<xceed:DateTimePicker Margin="4" Width="160" Name="dtpMaxX"
Format="Custom" FormatString="yyyy/MM/dd HH:mm:ss"
Value="{Binding TimeStampMax, Mode=TwoWay}"/>
</StackPanel>
</Grid>
Вот мой DataPoint
класс:
public class DataPoint
{
public DataPoint() { }
public DataPoint(DateTime timeStamp, double value)
{
TimeStamp = timeStamp;
Value = value;
}
public double Value { get; set; }
public DateTime TimeStamp { get; set; }
}
А вот мой PlotGraph()
метод, который выполняет всю работу по построению графиков. Я включу весь код MainWindow()
внизу этого поста, если вы хотите воспроизвести это приложение.
private void PlotGraph()
{
var mapper = Mappers.Xy<DataPoint>()
.X(dp => dp.TimeStamp.Ticks)
.Y(dp => dp.Value);
SeriesCollection = new SeriesCollection(mapper);
var lineSeries = new LineSeries
{
Values = DataPoints.AsChartValues(),
Fill = Brushes.Transparent
};
SeriesCollection.Add(lineSeries);
TimeStampMin = DataPoints.FirstOrDefault().TimeStamp;
TimeStampMax = DataPoints.LastOrDefault().TimeStamp;
Formatter = value => new DateTime((long)value).ToString("MM/dd/yy HH:mm:ss");
DataContext = this;
}
Теперь, когда я запускаю это и увеличиваю / уменьшаю масштаб с помощью мыши, обновленное конечное значениемои метки времени будут отлично отображаться на элементах управления DateTimePicker
. Однако, если я попытаюсь установить значение в элементах управления DateTimePicker
для увеличения / уменьшения, оно не будет работать. При попытке в моем окне Output
я получаю два следующих сообщения об ошибках, связанных с привязкой:
System.Windows.Data Ошибка: 5: значение, созданное BindingExpression, недопустимо для целевого свойства. ;Значение = '10 / 09/2019 15:50:41 'BindingExpression: Path = TimeStampMin;DataItem = 'MainWindow' (Name = '');целевым элементом является «Ось» (Name = '');свойство target равно MinValue (тип Double)
System.Windows.Data Ошибка: 5: значение, созданное BindingExpression, недопустимо для целевого свойства .;Значение = '10 / 09/2019 16:00:54 'BindingExpression: Path = TimeStampMax;DataItem = 'MainWindow' (Name = '');целевым элементом является «Ось» (Name = '');Свойство target - MaxValue (тип Double)
Это говорит мне, что проблема в привязке, что Axis.MinValue
и Axis.MaxValue
ожидают двойного значения, тогда как мои TimeStampMin
и TimeStampMax
- это, очевидно, DateTime
объекты. Как бы я сделал преобразование, чтобы получить двустороннее увеличение?
Здесь - это весь мой код MainWindow
, если вы хотите его воспроизвести. Я использую MVVMLight
инструментарий для команд и т. Д., Поэтому вам может потребоваться получить пакет NuGet
, если вы хотите запустить его как есть.
Похоже, что некоторые люди не могут получить доступ к ссылке, поэтомувот полный код:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public SeriesCollection SeriesCollection
{
get;
set;
}
public Func<double, string> Formatter
{
get;
set;
}
private DateTime _timeStampMin;
public DateTime TimeStampMin
{
get
{
return _timeStampMin;
}
set
{
if (_timeStampMin == value)
return;
_timeStampMin = value;
OnPropertyChanged("TimeStampMin");
}
}
private DateTime _timeStampMax;
public DateTime TimeStampMax
{
get
{
return _timeStampMax;
}
set
{
if (_timeStampMax == value)
return;
_timeStampMax = value;
OnPropertyChanged("TimeStampMax");
}
}
public List<DataPoint> DataPoints
{
get;
set;
}
public RelayCommand<PreviewRangeChangedEventArgs> XRangeChangedCommand
{
get;
private set;
}
public MainWindow()
{
InitializeComponent();
XRangeChangedCommand = new RelayCommand<PreviewRangeChangedEventArgs>(e => XRangeChanged(e));
InitializeData();
PlotGraph();
}
private void InitializeData()
{
var now = DateTime.Now;
DataPoints = new List<DataPoint>{new DataPoint()
{Value = 1, TimeStamp = now.AddMinutes(1)}, new DataPoint()
{Value = 4, TimeStamp = now.AddMinutes(2)}, new DataPoint()
{Value = 9, TimeStamp = now.AddMinutes(3)}, new DataPoint()
{Value = 16, TimeStamp = now.AddMinutes(4)}, new DataPoint()
{Value = 25, TimeStamp = now.AddMinutes(5)}, new DataPoint()
{Value = 36, TimeStamp = now.AddMinutes(6)}, new DataPoint()
{Value = 49, TimeStamp = now.AddMinutes(7)}, new DataPoint()
{Value = 64, TimeStamp = now.AddMinutes(8)}, new DataPoint()
{Value = 81, TimeStamp = now.AddMinutes(9)}, new DataPoint()
{Value = 100, TimeStamp = now.AddMinutes(10)}, new DataPoint()
{Value = 11 * 11, TimeStamp = now.AddMinutes(11)}, new DataPoint()
{Value = 12 * 12, TimeStamp = now.AddMinutes(12)}, new DataPoint()
{Value = 13 * 13, TimeStamp = now.AddMinutes(13)}, new DataPoint()
{Value = 14 * 14, TimeStamp = now.AddMinutes(14)}, new DataPoint()
{Value = 15 * 15, TimeStamp = now.AddMinutes(15)}, new DataPoint()
{Value = 16 * 16, TimeStamp = now.AddMinutes(16)}, new DataPoint()
{Value = 17 * 17, TimeStamp = now.AddMinutes(17)}, new DataPoint()
{Value = 18 * 18, TimeStamp = now.AddMinutes(18)}, new DataPoint()
{Value = 19 * 19, TimeStamp = now.AddMinutes(19)}, new DataPoint()
{Value = 20 * 20, TimeStamp = now.AddMinutes(20)}, };
}
private void PlotGraph()
{
var mapper = Mappers.Xy<DataPoint>().X(dp => dp.TimeStamp.Ticks).Y(dp => dp.Value);
SeriesCollection = new SeriesCollection(mapper);
var lineSeries = new LineSeries{Values = DataPoints.AsChartValues(), Fill = Brushes.Transparent};
SeriesCollection.Add(lineSeries);
TimeStampMin = DataPoints.FirstOrDefault().TimeStamp;
TimeStampMax = DataPoints.LastOrDefault().TimeStamp;
Formatter = value => new DateTime((long)value).ToString("MM/dd/yy HH:mm:ss");
DataContext = this;
}
public void XRangeChanged(PreviewRangeChangedEventArgs e)
{
TimeStampMin = DateTime.FromBinary((long)e.PreviewMinValue);
TimeStampMax = DateTime.FromBinary((long)e.PreviewMaxValue);
}
}