WPF MVVM Chart изменить оси - PullRequest
3 голосов
/ 11 июня 2010

Я новичок в WPF и MVVM.Я изо всех сил пытаюсь определить лучший способ изменить представление диаграммы.То есть изначально диаграмма может иметь оси: X - ID, Y - Длина, а затем после того, как пользователь изменит представление (через lisbox, radiobutton и т. Д.), Диаграмма будет отображать информацию: X - Длина, Y - IDи после третьего изменения пользователем он может отображать новый контент: X - ID, Y - качество.

Моя первоначальная мысль заключалась в том, что лучший способ сделать это - изменить сами привязки.Но я не знаю, как сказать элементу управления в XAML связывать, используя объект Binding в ViewModel, или безопасно ли изменять это связывание во время выполнения?

Тогда я подумал, может быть, у меня может быть просто универсальная модельу которого есть элементы X и Y и заполнить их по мере необходимости в модели представления?

Моя последняя мысль была о том, что я могу иметь 3 различных элемента управления диаграммой и просто скрывать и отображать их соответствующим образом.

Что такоеПРАВИЛЬНЫЙ / ПРЕДЛАГАЕМЫЙ способ сделать это в шаблоне MVVM?Будем весьма благодарны за любые примеры кода.

Спасибо

Вот что я имею за метод привязки к привязкам:

XAML:

        <charting:Chart.Series>
            <charting:BubbleSeries Name="bubbleSeries1"
                                   ClipToBounds="False"
                                   model:MakeDependencyProperty.IndependentValueBinding="{Binding AxisChoice.XBinding}"
                                   model:MakeDependencyProperty.DependentValueBinding="{Binding AxisChoice.YBinding}"
                                   model:MakeDependencyProperty.SizeValueBinding="{Binding AxisChoice.SizeBinding}"
                                   IsSelectionEnabled="True" SelectionChanged="bubbleSeries1_SelectionChanged"
                                   ItemsSource="{Binding Data}">
            </charting:BubbleSeries>
        </charting:Chart.Series>

        <ComboBox Height="100" Name="listBox1" Width="120" SelectedItem="{Binding AxisChoice}">
            <model:AxisGroup XBinding="{Binding Performance}" YBinding="{Binding TotalCount}" SizeBinding="{Binding TotalCount}" Selector.IsSelected="True"/>
            <model:AxisGroup XBinding="{Binding ID}" YBinding="{Binding TotalCount}" SizeBinding="{Binding BadPerformance}"/>
            <model:AxisGroup XBinding="{Binding ID}" YBinding="{Binding BadPerformance}" SizeBinding="{Binding TotalCount}"/>
        </ComboBox>

AxisGroup:

public class AxisGroup : DependencyObject// : FrameworkElement
{
    public Binding XBinding { get; set; }
    public Binding YBinding { get; set; }
    public Binding SizeBinding { get; set; }
}

DP:

public class MakeDependencyProperty : DependencyObject
{
    public static Binding GetIndependentValueBinding(DependencyObject obj) { return (Binding)obj.GetValue(IndependentValueBindingProperty); }
    public static void SetIndependentValueBinding(DependencyObject obj, Binding value) { obj.SetValue(IndependentValueBindingProperty, value); }
    public static readonly DependencyProperty IndependentValueBindingProperty =
        DependencyProperty.RegisterAttached("IndependentValueBinding", typeof(Binding), typeof(MakeDependencyProperty), new PropertyMetadata { PropertyChangedCallback = (obj, e) => { ((BubbleSeries)obj).IndependentValueBinding = (Binding)e.NewValue;}});


    public static Binding GetDependentValueBinding(DependencyObject obj) { return (Binding)obj.GetValue(DependentValueBindingProperty); }
    public static void SetDependentValueBinding(DependencyObject obj, Binding value) { obj.SetValue(DependentValueBindingProperty, value); }
    public static readonly DependencyProperty DependentValueBindingProperty =
        DependencyProperty.RegisterAttached("DependentValueBinding", typeof(Binding), typeof(MakeDependencyProperty), new PropertyMetadata { PropertyChangedCallback = (obj, e) => { ((BubbleSeries)obj).DependentValueBinding = (Binding)e.NewValue; } });

    public static Binding GetSizeValueBinding(DependencyObject obj) { return (Binding)obj.GetValue(SizeValueBindingProperty); }
    public static void SetSizeValueBinding(DependencyObject obj, Binding value) { obj.SetValue(SizeValueBindingProperty, value); }
    public static readonly DependencyProperty SizeValueBindingProperty =
        DependencyProperty.RegisterAttached("SizeValueBinding", typeof(Binding), typeof(MakeDependencyProperty), new PropertyMetadata { PropertyChangedCallback = (obj, e) => { ((BubbleSeries)obj).SizeValueBinding = (Binding)e.NewValue; } }); 
}

ViewModel:

public class BubbleViewModel : BindableObject
{
    private IEnumerable<SessionPerformanceInfo> data;
    public IEnumerable<SessionPerformanceInfo> Data { ... }

    public AxisGroup AxisChoice;
}

Создается следующее исключение: + $ exception {"Значение не может быть нулевым. \ R\ nПараметр имени: привязка "} System.Exception {System.ArgumentNullException}

Имеет отношение к 4 привязкам в bubbleSeries.Скорее всего, я делаю что-то не так с путями привязки, но, как я уже сказал, я новичок в связывании и wpf, поэтому любые советы будут с благодарностью.

Ответы [ 2 ]

4 голосов
/ 11 июня 2010

Ваша первоначальная мысль была правильной: вы можете привязать к привязкам, например, если вы хотите изменить обе оси вместе, у вас может быть ComboBox, подобный этому:

<ComboBox SelectedItem="{Binding AxisChoice}">
  <my:AxisChoice XBinding="{Binding ID}" YBinding="{Binding Length}" />
  <my:AxisChoice XBinding="{Binding Length}" YBinding="{Binding ID}" />
  <my:AxisChoice XBinding="{Binding ID}" YBinding="{Binding Quality}" />
</ComboBox>

Чтобы сделать эту работу, вы должны объявитьСвойства XBinding и YBinding как CLR типа «Binding»:

public class AxisChoice
{
  public Binding XBinding { get; set; }
  public Binding YBinding { get; set; }
}

В идеале вы можете просто связать DependentValueBinding или IndependentValueBinding вашей диаграммы:

<Chart ...>
  <LineSeries
    DependentValueBinding="{Binding AxisChoice.XBinding}"
    IndependentValueBinding="{Binding AxisChoice.YBinding}" />
</Chart>

К сожалению, это не работает, потому чтоDependentValueBinding и IndependentValueBinding не являются DependencyProperties.

Временное решение заключается в создании присоединенного DependencyProperty для отражения каждого свойства, которое не является DependencyProperty, например:

public class MakeDP : DependencyObject
{
  public static Binding GetIndependentValueBinding(DependencyObject obj) { return (Binding)obj.GetValue(IndependentValueBindingProperty); }
  public static void SetIndependentValueBinding(DependencyObject obj, Binding value) { obj.SetValue(IndependentValueBindingProperty, value); }
  public static readonly DependencyProperty IndependentValueBindingProperty = DependencyProperty.RegisterAttached("IndependentValueBinding", typeof(Binding), typeof(MakeDP), new PropertyMetadata
  {
    PropertyChangedCallback = (obj, e) =>
    {
      ((DataPointSeries)obj).IndependentValueBinding = (Binding)e.NewValue;
    }
  });

  public static Binding GetDependentValueBinding(DependencyObject obj) { return (Binding)obj.GetValue(DependentValueBindingProperty); }
  public static void SetDependentValueBinding(DependencyObject obj, Binding value) { obj.SetValue(DependentValueBindingProperty, value); }
  public static readonly DependencyProperty DependentValueBindingProperty = DependencyProperty.RegisterAttached("DependentValueBinding", typeof(Binding), typeof(MakeDP), new PropertyMetadata
  {
    PropertyChangedCallback = (obj, e) =>
      {
        ((DataPointSeries)obj).DependentValueBinding = (Binding)e.NewValue;
      }
  });

}

Таким образом, ваш XAML становится:

<Chart ...>
  <LineSeries
    my:MakeDP.DependentValueBinding="{Binding AxisChoice.XBinding}"
    my:MakeDP.IndependentValueBinding="{Binding AxisChoice,YBinding}" />
</Chart>

Если вместо этого вы хотите изменить оси отдельно (два отдельных ComboBox или ListBoxes), вам не нужен AxisChoice: просто сделайте Items или ItemsSource каждого ComboBox состоящими из привязок и поместите XBinding «a»Свойства "и" YBinding "прямо в режиме просмотраl.

Обратите внимание, что если ваш элемент управления предоставляет обычное свойство вместо свойства типа Binding, вы все равно можете использовать этот метод, но в этом случае вы будете использовать BindingOperations.SetBinding вместо простого хранения значения привязки.

Например, если вы хотите изменить привязку текста в TextBlock с:

<TextBlock Text="{Binding FirstName}" />

на

<TextBlock Text="{Binding LastName}" />

на основе выбора ComboBox или ListBox,Вы можете использовать прикрепленное свойство следующим образом:

<TextBlock my:BindingHelper.TextBinding="{Binding XBinding}" />

Реализация присоединенного свойства тривиальна:

public class BindingHelper : DependencyObject
{
  public static BindingBase GetTextBinding(DependencyObject obj) { return (BindingBase)obj.GetValue(TextBindingProperty); }
  public static void SetTextBinding(DependencyObject obj, BindingBase value) { obj.SetValue(TextBindingProperty, value); }
  public static readonly DependencyProperty TextBindingProperty = DependencyProperty.RegisterAttached("TextBinding", typeof(BindingBase), typeof(BindingHelper), new PropertyMetadata
  {
    PropertyChangedCallback = (obj, e) =>
      BindingOperations.SetBinding(obj, TextBlock.TextProperty, (BindingBase)e.NewValue)
  });
}
0 голосов
/ 12 октября 2010

Я пытаюсь упростить вещи, поэтому я сделал ItemsSource ComboBox (Y1-Axis) состоящим из наблюдаемой коллекции привязок, и я поместил свойство «YBinding» непосредственно в ViewModel и установил свойство публичной привязки как комбинированный список SelectedItem.

Привязка зависимых значений приводит к сбою приложения, хотя при использовании публичной привязки SelectedY1:

<ComboBox Height="22" Name="comboBox1" 
            DisplayMemberPath="Source.MetricVarName"                           
            ItemsSource="{Binding AllY1Choices}"   
            SelectedIndex="0" 
            SelectedItem="{Binding SelectedY1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</ComboBox>

<chartingToolkit:LineSeries
        ItemsSource="{Binding AllY1Axis}"
        IndependentValueBinding="{Binding AccumDate}"                            
    my:MakeDP.DependentValueBinding="{Binding SelectedY1}">

В ВМ:

private Binding _Y1axisChoice = new Binding();
private ObservableCollection<Binding> _allY1Choices = new ObservableCollection<Binding>();
public ObservableCollection<Binding> AllY1Choices
{
    get { return _allY1Choices; }
    set
    {
    _allY1Choices = value;
    OnPropertyChanged("AllY1Choices");
    }
}

private Binding _selectedY1 = new Binding();
public Binding SelectedY1
{
    get { return _selectedY1; }
    set
    {
        if (_selectedY1 != value)
        {
            _selectedY1 = value;
            OnPropertyChanged("SelectedY1");                    
        }
    }
}

В виртуальном конструкторе:

_Y1axisChoice = new Binding("MetricVarID");
_Y1axisChoice.Source = AllY1MetricVars[0];
_selectedY1 = _Y1axisChoice; // set default for combobox

_allY1Choices.Add(_Y1axisChoice);
_Y1axisChoice = new Binding("MetricVarID");
_Y1axisChoice.Source = AllY1MetricVars[1];

_allY1Choices.Add(_Y1axisChoice);

Есть мысли по этому поводу? Объект привязки «SelectedY1» имеет Source.MetricID = «OldA», и это допустимое значение для привязки зависимого значения.

Ошибка: Исключение типа «System.InvalidOperationException» произошло в System.Windows.Controls.DataVisualization.Toolkit.dll, но не было обработано в коде пользователя

Дополнительная информация: Назначенная зависимая ось не может быть использована. Это может быть связано с отсутствием свойства Ориентация для оси или несоответствием типов между отображаемыми значениями и значениями, поддерживаемыми осью.

Спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...