I have a custom control with two ComboBoxes with hard coded ComboBoxItems in them and I would like to be able to bind to the values via a single DependencyProperty but can't seem to get the bindings working. Maybe my approach is way off, but how should I do to get it working?
Generic.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyApp.Components">
<Style TargetType="{x:Type local:ContractLimitSelector}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ContractLimitSelector}">
<ControlTemplate.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</ControlTemplate.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<ComboBox x:Name="PART_ComboAA" Grid.Column="0" SelectedValue="{TemplateBinding SelectedAA}" />
<ComboBox x:Name="PART_ComboFA" Grid.Column="1" SelectedValue="{TemplateBinding SelectedFA}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Custom Control:
public class SelectorItems
{
public string AA { get; set; }
public string FA { get; set; }
}
public class ContractLimitSelector : Control
{
private static List<string> ComboBoxSource = new List<string>()
{
"-",
"BE",
"EE",
};
static ContractLimitSelector()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ContractLimitSelector), new FrameworkPropertyMetadata(typeof(ContractLimitSelector)));
}
public override void OnApplyTemplate()
{
var comboAA = Template.FindName("PART_ComboAA", this) as ComboBox;
var comboFA = Template.FindName("PART_ComboFA", this) as ComboBox;
comboAA.ItemsSource = ComboBoxSource;
comboFA.ItemsSource = ComboBoxSource;
base.OnApplyTemplate();
}
private SelectorItems GetAllValues()
{
var AA = (string)GetValue(SelectedAAProperty);
var FA = (string)GetValue(SelectedFAProperty);
return new SelectorItems() { AA = AA, FA = FA };
}
public static readonly DependencyProperty VisibleHeaderProperty =
DependencyProperty.Register("VisibleHeader", typeof(bool), typeof(ContractLimitSelector),
new PropertyMetadata(false));
public bool VisibleHeader
{
get { return (bool)GetValue(VisibleHeaderProperty); }
set { SetValue(VisibleHeaderProperty, value); }
}
public static readonly DependencyProperty SelectedAAProperty =
DependencyProperty.Register("SelectedAA", typeof(string), typeof(ContractLimitSelector),
new PropertyMetadata(string.Empty));
public string SelectedAA
{
get { return (string)GetValue(SelectedAAProperty); }
set
{
var all = GetAllValues();
SetValue(SelectedValuesProperty, new SelectorItems() { AA = value, FA = all.FA, });
SetValue(SelectedAAProperty, value);
}
}
public static readonly DependencyProperty SelectedFAProperty =
DependencyProperty.Register("SelectedFA", typeof(string), typeof(ContractLimitSelector),
new PropertyMetadata(string.Empty));
public string SelectedFA
{
get { return (string)GetValue(SelectedFAProperty); }
set
{
var all = GetAllValues();
SetValue(SelectedValuesProperty, new SelectorItems() { AA = all.AA, FA = value, });
SetValue(SelectedFAProperty, value);
}
}
public SelectorItems SelectedValues
{
get
{
return new SelectorItems()
{
AA = (string)GetValue(SelectedAAProperty),
FA = (string)GetValue(SelectedFAProperty),
};
}
set
{
SetValue(SelectedAAProperty, value.AA);
SetValue(SelectedFAProperty, value.FA);
}
}
public static readonly DependencyProperty SelectedValuesProperty =
DependencyProperty.Register("SelectedValues", typeof(SelectorItems), typeof(ContractLimitSelector),
new PropertyMetadata(new SelectorItems()));
}
I use it like this: XAML:
<custom:ContractLimitSelector SelectedValues="{Binding PrepareLockHouseValue, Mode=TwoWay}" />
ViewModel:
private SelectorItems _contractValues;
public SelectorItems ContractValues
{
get
{
return _contractValues;
}
set
{
_contractValues = value;
OnPropertyChanged(nameof(ContractValues));
}
}
I thought using SetValue whenever any of the ComboBoxes change would trigger the "shared" SelectedValues DependecyProperty, but nothing ever gets triggered...
What am I missing?
CodePudding user response:
The SelectedAA
and SelectedFA
property setters are not called when you call
SetValue(SelectedAAProperty, value.AA);
SetValue(SelectedFAProperty, value.FA);
You would have to write
SelectedAA = value.AA;
SelectedFA = value.FA;
Better move all code except
SetValue(SelectedAAProperty, value);
and
SetValue(SelectedFAProperty, value);
out of the setters and add PropertyChangedCallbacks to execute the other code.
The properties would then also properly work with data bindings and other possible value sources.
In general, the get and set methods of the CLR wrapper of a dependency property must not contain anything else than the GetValue
and SetValue
calls, because get/set may be bypassed by the framework.
See XAML Loading and Dependency Properties for details.