我正在动态创建一个组合框控件,该控件在运行时添加到视图中。
var comboBox = new ComboBox();
comboBox.Height = 21;
comboBox.Width = 75;
var margin = comboBox.Margin;
margin.Right += 5;
comboBox.Margin = margin;
comboBox.SetBinding(ItemsControl.ItemsSourceProperty, new Binding($"SearchDescriptor.SelectedFilter.FilterControls[{InputPosition}].Conditions"));
comboBox.IsSynchronizedWithCurrentItem = true;
comboBox.SelectedValuePath = "ConditionOperator";
comboBox.DisplayMemberPath = "Text";
comboBox.SetBinding(Selector.SelectedItemProperty, new Binding($"SearchDescriptor.SelectedFilter.FilterControls[{InputPosition}].SelectedCondition"));
Grid.SetColumn(comboBox, 1);
return comboBox;
这是生成组合框控件的代码。控件本身放置在一个视图上,该视图将DataContext设置为某个具有名为
的属性的视图模型SearchDescriptor
此属性具有选定的过滤器属性,该属性包含控件对象的集合。这些控制对象负责生成控件并设置绑定。
首先我要说的是,最初绑定有效,但是一旦我开始从组合框中选择选项,它就不会更新它绑定的属性。 这很奇怪,因为路径显然是正确的,否则它最初不会绑定属性。
我查看了与此问题有关的所有问题,并尝试了所有方法但无济于事。
SelectedItem绑定到名为SelectedCondition的属性,该属性为Condition类,该类如下所示:
public struct Condition
{
public ConditionOperator ConditionOperator { get; }
public string Text { get; }
public Condition(ConditionOperator conditionOperator, string text)
{
ConditionOperator = conditionOperator;
Text = text;
}
}
修改 实现属性SelectedCondition
的类public class SearchDescriptorFilterControl
{
private SearchDescriptorFilter m_filter;
private IEnumerable<ConditionOperator> m_choosableConditions;
private object m_value;
public SearchDescriptorFilter Filter
{
get
{
return m_filter;
}
set
{
if (m_filter != null)
throw new Exception("Filter can be set only once.");
m_filter = value;
}
}
public string Label { get; set; }
public double? LabelWidth { get; set; }
public HorizontalAlignment LabelContentAlignment { get; set; } = HorizontalAlignment.Left;
public double Width { get; set; } = 100;
public string ConditionExpression { get; set; }
public FilterType Type { get; set; }
private Condition m_conditionOperator;
public Condition SelectedCondition
{
get
{
return m_conditionOperator;
}
set
{
m_conditionOperator = value;
}
}
public IEnumerable<ConditionOperator> ChoosableConditions
{
get
{
return m_choosableConditions;
}
set
{
var mappings = new Dictionary<ConditionOperator, string>()
{
[ConditionOperator.Contains] = "Contains",
[ConditionOperator.EndsWith] = "Ends with",
[ConditionOperator.Equals] = "Equals",
[ConditionOperator.Greater] = "Greater",
[ConditionOperator.GreaterOrEqual] = "Greater or equal",
[ConditionOperator.Less] = "Less",
[ConditionOperator.LessOrEqual] = "Less or equal",
[ConditionOperator.StartsWith] = "Starts with"
};
m_choosableConditions = value;
if (value != null && value.Any())
{
//Conditions = new Condition[value.Count()];
//int i = 0;
foreach (var condition in value)
{
Conditions.Add(new Condition(condition, mappings[condition]));
//Conditions[i] = new Condition(condition, mappings[condition]);
//i++;
}
}
}
}
public List<Condition> Conditions { get; private set; } = new List<Condition>();
public object Value
{
get
{
return m_value;
}
set
{
m_value = value;
}
}
private bool ShouldShowOperatorsComboBox
{
get
{
return ChoosableConditions != null && ChoosableConditions.Any();
}
}
private int InputPosition
{
get
{
int i = 0;
foreach (var filterControl in Filter.FilterControls)
{
if (filterControl == this)
return i;
i++;
}
throw new Exception($"Input cannot be found for filter {Filter.Name} and control {Label}.");
}
}
public SearchDescriptorFilterControl() { }
private Grid GetGrid()
{
var grid = new Grid();
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
if (ShouldShowOperatorsComboBox)
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
return grid;
}
private Label GetLabel()
{
var label = new Label();
label.Content = Label;
if (LabelWidth.HasValue)
label.Width = LabelWidth.Value;
else
{
var margin = label.Margin;
margin.Right += 5;
label.Margin = margin;
}
label.HorizontalContentAlignment = LabelContentAlignment;
Grid.SetColumn(label, 0);
return label;
}
private ComboBox GetConditionsComboBox()
{
var comboBox = new ComboBox();
comboBox.Height = 21;
comboBox.Width = 75;
var margin = comboBox.Margin;
margin.Right += 5;
comboBox.Margin = margin;
comboBox.SetBinding(ItemsControl.ItemsSourceProperty, new Binding($"SearchDescriptor.SelectedFilter.FilterControls[{InputPosition}].Conditions"));
comboBox.IsSynchronizedWithCurrentItem = true;
comboBox.SelectedValuePath = nameof(Condition.ConditionOperator);
comboBox.DisplayMemberPath = nameof(Condition.Text);
comboBox.SetBinding(Selector.SelectedItemProperty, new Binding($"SearchDescriptor.SelectedFilter.FilterControls[{InputPosition}].SelectedCondition")
{
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
Grid.SetColumn(comboBox, 1);
return comboBox;
}
private TextBox GetTextInput()
{
var input = new TextBox();
input.SetBinding(TextBox.TextProperty, new Binding($"SearchDescriptor.SelectedFilter.FilterControls[{InputPosition}].Value") { Delay = 1000, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
return input;
}
private DatePicker GetDateInput()
{
var input = new DatePicker();
input.SetBinding(DatePicker.SelectedDateProperty, new Binding($"SearchDescriptor.SelectedFilter.FilterControls[{InputPosition}].Value") { Delay = 1000, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
return input;
}
public Grid GetInputFilter()
{
var grid = GetGrid();
grid.Children.Add(GetLabel());
//At the moment the column for filter input is 1 - immediately after the label.
var inputColumn = 1;
// If the collection has any element that means we must supply
// condition combo box so the user can choose a condition operator.
// For that we create another column.
if (ShouldShowOperatorsComboBox)
{
var comboBox = GetConditionsComboBox();
grid.Children.Add(comboBox);
//Combo box comes after the label which means
//input filter comes after the combo box so we
//will increment the inputColumn value by 1.
inputColumn++;
}
//Filter input.
FrameworkElement inputFilter;
if (Type == FilterType.Date)
inputFilter = GetDateInput();
else
inputFilter = GetTextInput();
inputFilter.Width = Width;
Grid.SetColumn(inputFilter, inputColumn);
grid.Children.Add(inputFilter);
return grid;
}
}
答案 0 :(得分:1)
绑定到SelectedValuePath
媒体资源时,您不需要SelectedItem
。此外,由于您似乎在定义源属性的同一个类中创建了ComboBox
,因此您也可以指定绑定的Source
,如下所示:
private ComboBox GetConditionsComboBox()
{
var comboBox = new ComboBox();
comboBox.Height = 21;
comboBox.Width = 75;
var margin = comboBox.Margin;
margin.Right += 5;
comboBox.Margin = margin;
comboBox.SetBinding(ItemsControl.ItemsSourceProperty, new Binding("Conditions") { Source = this });
comboBox.IsSynchronizedWithCurrentItem = true;
comboBox.DisplayMemberPath = nameof(Condition.Text);
comboBox.SetBinding(Selector.SelectedItemProperty, new Binding("SelectedCondition")
{
Source = this,
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
Grid.SetColumn(comboBox, 1);
return comboBox;
}