我是WPF和MVVM的新手。我正在努力确定改变图表视图的最佳方法。也就是说,最初图表可能有轴:X - ID,Y - 长度,然后在用户更改视图后(通过lisbox,radiobutton等),图表将显示以下信息:X - 长度,Y - ID ,在用户进行第三次更改后,它可能会显示新内容:X - ID,Y - 质量。
我最初的想法是,最好的方法是更改绑定本身。但我不知道如何告诉XAML中的控件使用ViewModel中的Binding对象绑定,或者在运行时更改绑定是否安全?
然后我想也许我可以拥有一个具有成员X和Y的通用模型,并根据需要在viewmodel中填充它们?
我最后的想法是,我可以有3个不同的图表控件,只需隐藏并显示它们。
在MVVM模式中执行此操作的CORRECT / SUGGESTED方法是什么?任何代码示例都将非常感激。
由于
以下是绑定到绑定方法的内容:
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; } });
}
视图模型:
public class BubbleViewModel : BindableObject
{
private IEnumerable<SessionPerformanceInfo> data;
public IEnumerable<SessionPerformanceInfo> Data { ... }
public AxisGroup AxisChoice;
}
这会产生以下异常: + $ exception {“Value不能为null。\ r \ nParameter name:binding”} System.Exception {System.ArgumentNullException}
与bubbleSeries中的4个绑定有关。我很可能在绑定路径上做错了,但正如我所说,我是绑定和wpf的新手,所以任何提示都会非常感激。
答案 0 :(得分:4)
您最初的想法是正确的:您可以绑定到绑定,例如,如果您想要将两个轴一起更改,您可能会有这样的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声明为“Binding”类型的CLR属性:
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或ListBox),则不需要AxisChoice:只需使每个ComboBox的Items或ItemsSource由绑定组成,并放置一个“XBinding”和“YBinding”直接在视图模型中的属性。
请注意,如果您的控件公开常规属性而不是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)
});
}
答案 1 :(得分:0)
我正在尝试简化事情,所以我使ComboBox(Y1-Axis)的ItemsSource由一个可观察的绑定集合组成,我将“YBinding”属性直接放在ViewModel中,并将公共绑定属性设置为组合框SelectedItem。
在使用public Binding SelectedY1时,dependentvaluebinding正在崩溃应用程序:
<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}">
在VM中:
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");
}
}
}
在VM contstructor中:
_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.Windows.Controls.DataVisualization.Toolkit.dll中发生了'System.InvalidOperationException'类型的异常,但未在用户代码中处理
附加信息:不能使用分配的从属轴。这可能是由于轴的未设置Orientation属性或绘制的值与轴支持的值之间的类型不匹配。
由于