如何在 ComboBox TemplateSelector 中强制更新 WPF 多重绑定?
How to force a WPF multi-binding to update when inside a ComboBox TemplateSelector?
作为序言,这个问题来自扩展 this answer 如何使所选项目看起来不同于 ComboBox 中的下拉项目。
我正在尝试使我的自定义选定项使用 ComboBox 的 Tag 属性中的信息。因为我需要使用转换器,所以我使用 mutli-converter 以便能够将 "myself" 发送到转换 class。因此,我有这两个模板:
<DataTemplate x:Key="SelectedItemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource SelectedConverter}">
<Binding RelativeSource="{RelativeSource Self}" />
<Binding StringFormat="This is here so it's called every time" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="DropDownItemsTemplate">
<TextBlock Grid.Column="0" Text="{Binding}" Margin="0,0,10,0" VerticalAlignment="Center" />
</DataTemplate>
还有我的转换器:
class SelectedConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var retVal = "";
// The value passed in should be the TextBox in the ComboBoxItem
var element = values[0] as DependencyObject;
// Try to find it's parent RoleComboBox
while (element != null && !(element is ComboBox))
{
element = VisualTreeHelper.GetParent(element);
}
// If we didn't find anything, return an empty string
if (element == null) return retVal;
// Otherwise, get the role from the ComboBox
var tag = (element as ComboBox).Tag;
if (tag?.ToString().Contains("Custom") ?? false)
{
retVal = "Custom Stuff ";
}
return retVal;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML 组合框
<ComboBox Name="myComboBox" Grid.Column="0" Tag="My Custom Tag" ItemTemplateSelector="{StaticResource CbTemplateSelector}">
<ComboBox.Items>
<ComboBoxItem Content="A" />
<ComboBoxItem Content="B" />
<ComboBoxItem Content="C" />
<ComboBoxItem Content="D" />
<ComboBoxItem Content="E" />
</ComboBox.Items>
</ComboBox>
所有这一切都很好地产生了这个:
现在,我需要做的是在更改标签 属性 时将 "Custom Stuff C" 更改为其他内容。到目前为止,它只会在我更改所选项目时更改,但我需要它更改而无需用户将其更改为 D,然后再更改为 C。
从研究中,我尝试使用以下代码强制更新,但它不起作用。
myComboBox.GetBindingExpression(ComboBox.ItemTemplateProperty)?.UpdateTarget();
myComboBox.GetBindingExpression(ComboBox.ItemTemplateSelectorProperty)?.UpdateTarget();
myComboBox.GetBindingExpression(ComboBox.SelectionBoxItemTemplateProperty)?.UpdateTarget();
myComboBox.GetBindingExpression(ComboBox.TemplateProperty)?.UpdateTarget();
myComboBox.UpdateLayout();
myComboBox.OnSelectionChanged(new SelectionChangedEventArgs(SelectionChangedEvent, new List<bool> { }, new List<bool> { }));
请注意,我确实有一个继承自 ComboBox
的自定义控件,因此我确实可以访问受保护的方法(这就是上面最后一行代码的工作原理)。我只是提取了那部分,以便提供一小部分可重现的代码。
此时,我不确定还能尝试什么。那么,如何根据我的操作方式强制更新绑定?
无需绑定到自身然后在代码中搜索父组合框,只需使用内置方法即可:
<TextBlock.Text>
<MultiBinding Converter="{StaticResource SelectedConverter}">
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}" Path="Tag" />
<Binding StringFormat="This is here so it's called every time" />
</MultiBinding>
</TextBlock.Text>
作为奖励,如果您直接绑定到 ComboBox.Tag - 整个多重绑定将在标签更改时刷新。
作为序言,这个问题来自扩展 this answer 如何使所选项目看起来不同于 ComboBox 中的下拉项目。
我正在尝试使我的自定义选定项使用 ComboBox 的 Tag 属性中的信息。因为我需要使用转换器,所以我使用 mutli-converter 以便能够将 "myself" 发送到转换 class。因此,我有这两个模板:
<DataTemplate x:Key="SelectedItemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource SelectedConverter}">
<Binding RelativeSource="{RelativeSource Self}" />
<Binding StringFormat="This is here so it's called every time" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="DropDownItemsTemplate">
<TextBlock Grid.Column="0" Text="{Binding}" Margin="0,0,10,0" VerticalAlignment="Center" />
</DataTemplate>
还有我的转换器:
class SelectedConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var retVal = "";
// The value passed in should be the TextBox in the ComboBoxItem
var element = values[0] as DependencyObject;
// Try to find it's parent RoleComboBox
while (element != null && !(element is ComboBox))
{
element = VisualTreeHelper.GetParent(element);
}
// If we didn't find anything, return an empty string
if (element == null) return retVal;
// Otherwise, get the role from the ComboBox
var tag = (element as ComboBox).Tag;
if (tag?.ToString().Contains("Custom") ?? false)
{
retVal = "Custom Stuff ";
}
return retVal;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML 组合框
<ComboBox Name="myComboBox" Grid.Column="0" Tag="My Custom Tag" ItemTemplateSelector="{StaticResource CbTemplateSelector}">
<ComboBox.Items>
<ComboBoxItem Content="A" />
<ComboBoxItem Content="B" />
<ComboBoxItem Content="C" />
<ComboBoxItem Content="D" />
<ComboBoxItem Content="E" />
</ComboBox.Items>
</ComboBox>
所有这一切都很好地产生了这个:
现在,我需要做的是在更改标签 属性 时将 "Custom Stuff C" 更改为其他内容。到目前为止,它只会在我更改所选项目时更改,但我需要它更改而无需用户将其更改为 D,然后再更改为 C。
从研究中,我尝试使用以下代码强制更新,但它不起作用。
myComboBox.GetBindingExpression(ComboBox.ItemTemplateProperty)?.UpdateTarget();
myComboBox.GetBindingExpression(ComboBox.ItemTemplateSelectorProperty)?.UpdateTarget();
myComboBox.GetBindingExpression(ComboBox.SelectionBoxItemTemplateProperty)?.UpdateTarget();
myComboBox.GetBindingExpression(ComboBox.TemplateProperty)?.UpdateTarget();
myComboBox.UpdateLayout();
myComboBox.OnSelectionChanged(new SelectionChangedEventArgs(SelectionChangedEvent, new List<bool> { }, new List<bool> { }));
请注意,我确实有一个继承自 ComboBox
的自定义控件,因此我确实可以访问受保护的方法(这就是上面最后一行代码的工作原理)。我只是提取了那部分,以便提供一小部分可重现的代码。
此时,我不确定还能尝试什么。那么,如何根据我的操作方式强制更新绑定?
无需绑定到自身然后在代码中搜索父组合框,只需使用内置方法即可:
<TextBlock.Text>
<MultiBinding Converter="{StaticResource SelectedConverter}">
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}" Path="Tag" />
<Binding StringFormat="This is here so it's called every time" />
</MultiBinding>
</TextBlock.Text>
作为奖励,如果您直接绑定到 ComboBox.Tag - 整个多重绑定将在标签更改时刷新。