I have a custom WPF control (using UserControl as base) that exposes a bindable properties (using DependencyProperty). I want to disable editing in this control when one of the properties is a oneway binding.
public partial class OnOffControl : UserControl
{
...
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register(
"IsChecked",
typeof(bool?),
typeof(OnOffControl),
...
public bool? IsChecked
{
get
{
return (bool?)GetValue(IsCheckedProperty);
}
set
{
SetValue(IsCheckedProperty, value);
}
}
Usage point
<DataGridTemplateColumn Width="40" Header="State">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<UIUtil:OnOffControl
IndicatorType="SwitchIndicator"
IsChecked="{Binding Value, Mode=OneWay}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
So when IsChecked is a oneway binding I want to disable editing in OnOffControl. How does one go about detecting the property binding is OneWay inside of the control and then disable editing?
You may check if there is a Binding and get the Binding's properties in a PropertyChangedCallback:
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register(
nameof(IsChecked),
typeof(bool?),
typeof(OnOffControl),
new PropertyMetadata(IsCheckedPropertyChanged));
public bool? IsChecked
{
get { return (bool?)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}
private static void IsCheckedPropertyChanged(
DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var control = (OnOffControl)o;
var binding = control.GetBindingExpression(IsCheckedProperty)?.ParentBinding;
var enabled = false;
if (binding != null)
{
enabled = binding.Mode == BindingMode.TwoWay
|| binding.Mode == BindingMode.OneWayToSource;
}
control.IsEnabled = enabled;
}
Related
I have the following DataTemplate
<DataTemplate x:Key="ArchiveModeContentTemplate">
<Button Style="{x:Static ui:ButtonStyles.DrawingButtonLabel}" Grid.Row="1" Grid.Column="0" Foreground="{x:Static ui:UbiBrushes.UbiDarkBlue}"
Content="{StaticResource ValidateIcon48}" ui:StyleProperties.Label="{DynamicResource Archive}"
Command="{Binding ElementName=factory,Path=BuildPopup}">
<i:Interaction.Behaviors>
<pop:PopupFactory x:Name="factory" Factory="{Binding ConfirmArchivingFactory}" />
</i:Interaction.Behaviors>
</Button>
</DataTemplate>
PopupFactory has a Command BuildPopup. this Command is given to the button with a binding with ElementName.
The first time this dataTemplate is displayed, it work fine. The button get the command. But if this dataTemplate is unloaded then displayed again, the binding give to the button the command of the previous instance of PopupFactory and not the newly created instance.
I pass in the constructor of PopupFactory and it is attached to the new button. So it is not a problem of PopupFactory being shared between templates.
Why this is happening? is it a bug with a the xaml cache?
Edit
I have an even stranger bug now.
I changed the syntax to the following to have the binding elementName after the name declaration in the Xaml. Now the command is working correctly but the the second button which is using a binding RelativeSource to find a command named GoBack don't work anymore. I used snoop to check the binding and it complain that it can't find the command BuildPopup. WPF is getting crazy!
<Button Style="{x:Static ui:ButtonStyles.DrawingButtonLabel}" Grid.Row="1" Grid.Column="0" Foreground="{x:Static ui:UbiBrushes.UbiDarkBlue}"
Content="{StaticResource ValidateIcon48}" ui:StyleProperties.Label="{DynamicResource Archive}">
<i:Interaction.Behaviors>
<pop:PopupFactory x:Name="Archivefactory" Factory="{Binding ConfirmArchivingFactory}" IsSingleInstance="False" />
</i:Interaction.Behaviors>
<Button.Command>
<Binding ElementName="Archivefactory" Path="BuildPopup" />
</Button.Command>
</Button>
<Button Grid.Row="1" Grid.Column="1"
Style="{x:Static ui:ButtonStyles.DrawingButtonLabel}"
Content="{StaticResource CrossIcon48}"
Foreground="Green"
ui:StyleProperties.Label="{DynamicResource Cancel}"
Command="{Binding Path=GoBack, RelativeSource={RelativeSource AncestorType={x:Type ui:DrillDown}}}" />
Edit
Here the code of PopupFactory
public class PopupFactory : Behavior<UIElement>
{
public ICommand BuildPopup { get; private set; }
private bool _canExecute;
private IDisposable _canexecuteSubscription = null;
public IObservable<bool> CanExecuteSource
{
get { return (IObservable<bool>)GetValue(CanExecuteSourceProperty); }
set { SetValue(CanExecuteSourceProperty, value); }
}
// Using a DependencyProperty as the backing store for CanExecute. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CanExecuteSourceProperty =
DependencyProperty.Register("CanExecute", typeof(IObservable<bool>), typeof(PopupFactory), new PropertyMetadata(null));
private static void OnCanExecuteSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs arg)
{
var factory = obj as PopupFactory;
factory._canexecuteSubscription?.Dispose();
if (arg.NewValue != null)
{
factory._canexecuteSubscription = ((IObservable<bool>)arg.NewValue)
.ObserveOnDispatcher()
.Subscribe(factory.UpdateCanExecute);
}
}
private void UpdateCanExecute(bool value)
{
_canExecute = value;
((RelayCommand<object>)BuildPopup).RaiseCanExecuteChanged();
}
public IFactory Factory
{
get { return (IFactory)GetValue(FactoryProperty); }
set { SetValue(FactoryProperty, value); }
}
// Using a DependencyProperty as the backing store for Factory. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FactoryProperty =
DependencyProperty.Register("Factory", typeof(IFactory), typeof(PopupFactory), new PropertyMetadata(null, OnFactoryChanged));
private static void OnFactoryChanged(DependencyObject obj, DependencyPropertyChangedEventArgs arg)
{
var factory = obj as PopupFactory;
((RelayCommand<object>)factory.BuildPopup).RaiseCanExecuteChanged();
}
public UIElement PlacementTarget
{
get { return (UIElement)GetValue(PlacementTargetProperty); }
set { SetValue(PlacementTargetProperty, value); }
}
// Using a DependencyProperty as the backing store for PlacementTarget. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PlacementTargetProperty =
DependencyProperty.Register("PlacementTarget", typeof(UIElement), typeof(PopupFactory), new PropertyMetadata(null));
public PlacementMode Placement
{
get { return (PlacementMode)GetValue(PlacementProperty); }
set { SetValue(PlacementProperty, value); }
}
// Using a DependencyProperty as the backing store for Placement. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PlacementProperty =
DependencyProperty.Register("Placement", typeof(PlacementMode), typeof(PopupFactory), new PropertyMetadata(PlacementMode.Center));
public bool IsSingleInstance
{
get { return (bool)GetValue(IsSingleInstanceProperty); }
set { SetValue(IsSingleInstanceProperty, value); }
}
// Using a DependencyProperty as the backing store for IsSingleInsance. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsSingleInstanceProperty =
DependencyProperty.Register("IsSingleInstance", typeof(bool), typeof(PopupFactory), new PropertyMetadata(false));
private bool _singleInstanceShowed = false;
public PopupFactory()
{
BuildPopup = new RelayCommand<object>((f) =>
{
ShowPopup(f);
}, (p) =>
{
return _canExecute && Factory != null && !_singleInstanceShowed;
});
UpdateCanExecute(true);
}
public IOverlayContainer ShowPopup(object parameter)
{
var param = new PopupParameter() { Owner = AssociatedObject };
UIElement target = PlacementTarget != null ? PlacementTarget : AssociatedObject;
var item = Factory.Build(parameter);
param.Content = item.Item;
param.Owner = AssociatedObject;
param.RemoveCondition = item.DisposeStream;
var container = OverlayManager.ShowPopup(param);
var placement = new PopupRelativePlacement(container as FrameworkElement, target,
Placement, false);
item.PostFactory?.Invoke();
if (IsSingleInstance)
{
_singleInstanceShowed = true;
OverlayManager.PopupOperations.Where((op) => op.Id == container.Id && op.Operationtype == OverlayOperation.OpType.PopupRemoved)
.Once((_) =>
{
_singleInstanceShowed = false;
((RelayCommand<object>)BuildPopup).RaiseCanExecuteChanged();
});
}
return container;
}
}
Problem solved.
I moved the PopupFactory Behavior to a visual parent of the button. This way, the behavior is created before the button and WPF don't mess up the name resolution during the binding.
I have UserControl, lets call it as CustomDataGrid, that contains DataGrid. Remained content doesn't matter. SelectedItem property of DataGrid must be SelectedItem property of CustomDataGrid. And I wanna be able to use Binding with this property, cause I use MVVM pattern. So I have to declare SelectedItem as DependencyProperty in CustomDataGrid. But I have no ideas haw can I make it properly...
This is how DepedencyProperty-s is declared usually:
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
"SelectedItem", typeof(Object), typeof(CustomDataGrid),
new FrameworkPropertyMetadata(default(Object), SelectedItemPropertyCallback)
{
BindsTwoWayByDefault = true,
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
// Optionally
private static void SelectedItemPropertyCallback(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
// dataGrid - `DataGrid` nested in `UserControl`
((CustomDataGrid)obj).dataGrid.SelectedItem = e.NewValue;
}
// Obviously, it has no any link with nested `dataGrid`. This is the problem.
public Object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
So, how can I declare SelectedItem property correctly?
You could leverage the binding framework for wiring such properties from underlying objects to outer containers
example assuming CustomDataGrid as UserControl
class CustomDataGrid : UserControl
{
public CustomDataGrid()
{
Binding b = new Binding("SelectedItem");
b.Source = this;
b.Mode = BindingMode.TwoWay;
dataGrid.SetBinding(DataGrid.SelectedItemProperty, b);
}
public object SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectedItem. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object), typeof(CustomDataGrid), new PropertyMetadata(null));
}
I have created a property called SelectedItem in CustomDataGrid and set a two way binding to SelectedItem of the actual dataGrid inside.
so this will wire up these properties and will propagate any changes to and fro.
XAML solution!
Use this DependencyProperty:
public object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(CustomDataGrid ), new FrameworkPropertyMetadata(null)
{
BindsTwoWayByDefault = true,
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
Then make your outer CustomDataGrid UserControl XAML look like this:
<UserControl x:Class="CustomDataGrid">
<DataGrid ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type CustomDataGrid}}}"
SelectedItem="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type CustomDataGrid}}}">
</DataGrid>
</UserControl>
You can then use the CustomDataGrid control the same way as the DataGrid control when binding ItemsSource and SelectedItem to your view model.
Using the MVVM pattern, I've bound the SelectedIndex property of a combo box to a variable in my view model. I can change the combo box selection programmatically from the view model; however, when the user makes a selection from the interface (view), the view model variable is not updated.
Here is the XAML (snipet):
<ComboBox Width="100"
HorizontalContentAlignment="Center"
SelectedIndex="{Binding GroupSortIndex,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ComboBoxItem Content="Appearance"/>
<ComboBoxItem Content="Created"/>
<ComboBoxItem Content="Name"/>
</ComboBox>
Here is a portion of the view model:
public int GroupSortIndex
{
get { return (int)GetValue(GroupSortIndexProperty); }
set { SetValue(GroupSortIndexProperty, value); }
}
public static readonly DependencyProperty GroupSortIndexProperty =
DependencyProperty.Register("GroupSortIndex", typeof(int),
typeof(MainWindowViewModel), new UIPropertyMetadata(-1));
What do I need to do to have GroupSortIndex updated when the user makes a selection from the IU?
yes, The SelectedIndex property looks has a bug. i was this problem and i solved it by changing the SelectedIndex to SelectedItem.
Change XAML SelectedIndex to SelectedItem:
<ComboBox ItemsSource="{Binding Path=YourOptionsList}"
SelectedItem="{Binding SelectedOption}" />
Somewhere you must set the DataContext of your Window to reference the collection from your XAML.
and in your ViewModel write this:
public List<String> YourOptionsList { get { return (int)GetValue(YourOptionsListProperty); } set { SetValue(YourOptionsListProperty, value); } }
public static readonly DependencyProperty YourOptionsListProperty = DependencyProperty.Register("YourOptionsList", typeof(List<String>), typeof(MainWindowViewModel), new UIPropertyMetadata(new List<String>()));
public string SelectedOption { get { return (int)GetValue(SelectedOptionProperty); } set { SetValue(SelectedOptionProperty, value); } }
public static readonly DependencyProperty SelectedOptionProperty = DependencyProperty.Register("SelectedOption", typeof(String), typeof(MainWindowViewModel), new UIPropertyMetadata("none");
public MainWindowViewModel()
{
YourOptionsList =new List<String>();
YourOptionsList.Add("Appearance");
YourOptionsList.Add("Created");
YourOptionsList.Add("Name");
}
How can I Add a dependency property to a text box and bind the dependency property to a Boolean property in silver light. my Boolean property is in my view model.
ImageSearchIsFocused is the property which allows me to set the focus on a text box.
<TextBox Text="{Binding ImgSearch, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Behaviors>
<common:FocusBehavior HasInitialFocus="True" IsFocused="{Binding ImageSearchIsFocused, Mode=TwoWay}" ></common:FocusBehavior>
</i:Interaction.Behaviors>
</TextBox>
ImageIsFocused Property
bool _ImageSearchIsFocused;
public bool ImageSearchIsFocused
{
get { return _ImageSearchIsFocused; }
set
{
_ImageSearchIsFocused = value;
NotifyPropertyChanged("ImageSearchIsFocused");
}
}
If you want to add a dependency property, you're going to have the subclass the TextBox and add the dependency property to your subclass. Then you can bind that to whatever you like:
public class MyTextBox : TextBox
{
public static readonly DependencyProperty MyBooleanValueProperty = DependencyProperty.Register(
"MyBooleanValue", typeof(bool), typeof(MyTextBox),
new PropertyMetadata(new PropertyChangedCallback(MyBooleanValueChanged)));
public bool MyBooleanValue
{
get { return (bool)GetValue(MyBooleanValueProperty); }
set { SetValue(MyBooleanValueProperty, value); }
}
private static void MyBooleanValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var propValue = (bool)e.NewValue;
var control = d as MyTextBox;
// do something useful
}
}
I'm new to WPF and MVVM. I'm struggling to determine the best way to change the view of a chart. That is, initially a chart might have the axes: X - ID, Y - Length, and then after the user changes the view (either via lisbox, radiobutton, etc) the chart would display the information: X - Length, Y - ID, and after a third change by the user it might display new content: X - ID, Y - Quality.
My initial thought was that the best way to do this would be to change the bindings themselves. But I don't know how tell a control in XAML to bind using a Binding object in the ViewModel, or whether it's safe to change that binding in runtime?
Then I thought maybe I could just have a generic Model that has members X and Y and populate them as needed in the viewmodel?
My last thought was that I could have 3 different chart controls and just hide and show them as appropriate.
What is the CORRECT/SUGGESTED way to do this in the MVVM pattern? Any code examples would be greatly appreciated.
Thanks
Here's what I have for the bind to bindings method:
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;
}
This generates the following exception:
+ $exception {"Value cannot be null.\r\nParameter name: binding"} System.Exception {System.ArgumentNullException}
Has something to do with the 4 bindings in teh bubbleSeries. I'm more than likely doing something wrong with binding paths but as I said I'm new to binding and wpf, so any tips would be greatly appreciated.
Your initial thought was correct: You can bind to bindings, for example if you want to change both axes together you might have a ComboBox like this:
<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>
To make this work you need to declare XBinding and YBinding as CLR properties of type "Binding":
public class AxisChoice
{
public Binding XBinding { get; set; }
public Binding YBinding { get; set; }
}
Ideally you could then simply bind the DependentValueBinding or IndependentValueBinding of your chart:
<Chart ...>
<LineSeries
DependentValueBinding="{Binding AxisChoice.XBinding}"
IndependentValueBinding="{Binding AxisChoice.YBinding}" />
</Chart>
Unfortunately this does not work because DependentValueBinding and IndependentValueBinding aren't DependencyProperties.
The workaround is to create an attached DependencyProperty to mirror each property that is not a DependencyProperty, for example:
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;
}
});
}
So your XAML becomes:
<Chart ...>
<LineSeries
my:MakeDP.DependentValueBinding="{Binding AxisChoice.XBinding}"
my:MakeDP.IndependentValueBinding="{Binding AxisChoice,YBinding}" />
</Chart>
If instead you want to change axes separately (two separate ComboBoxes or ListBoxes), you don't need AxisChoice: Simply make the Items or ItemsSource of each ComboBox consist of bindings, and put the a "XBinding" and "YBinding" properties directly in your view model.
Note that if your control exposes a regular property instead of a property of type Binding you can still use this method, but in this case you will use BindingOperations.SetBinding instead of just storing the binding value.
For example, if you want to change the binding of the text in a TextBlock from:
<TextBlock Text="{Binding FirstName}" />
to
<TextBlock Text="{Binding LastName}" />
based on a ComboBox or ListBox selection, you can use an attached property as follows:
<TextBlock my:BindingHelper.TextBinding="{Binding XBinding}" />
The attached property implementation is trivial:
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)
});
}
I'm trying to simplify things so I made the ItemsSource of a ComboBox (Y1-Axis) consist of an observable collection of bindings, and I put the "YBinding" property directly in the ViewModel and set the public binding property as the combobox SelectedItem.
The the dependentvaluebinding is crashing the app though when using the public Binding 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}">
In the 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");
}
}
}
In the 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);
Any thoughts on this? The Binding object "SelectedY1" has Source.MetricID="OldA", and that's a valid value for the dependent value binding.
The error:
An exception of type 'System.InvalidOperationException' occurred in System.Windows.Controls.DataVisualization.Toolkit.dll but was not handled in user code
Additional information: Assigned dependent axis cannot be used. This may be due to an unset Orientation property for the axis or a type mismatch between the values being plotted and those supported by the axis.
Thanks