You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中DataTemplateSelector仅触发一次,更新InputMode时不生效问题

问题分析

你的核心问题是DataTemplateSelector仅在ContentControl首次绑定执行时触发一次,后续KeyViewModel.InputMode变更时,Selector不会重新评估并切换模板。根本原因是:

  • ContentControl的Content绑定的是MainViewModel实例,只要这个实例本身不变,WPF不会因为其内部嵌套属性(StreamDeck.SelectedKey.InputMode)的变化而重新调用模板选择器。
  • 模板选择器的触发逻辑依赖于Content属性的实例变更,而非其内部属性的变更。

解决方案

方案1:绑定到直接触发变更的属性(推荐)

将ContentControl的Content直接绑定到StreamDeck.SelectedKey.InputMode,这样当InputMode实例切换时,Content属性会更新,自动触发模板选择器:

1. 修改ContentControl绑定

<ContentControl Content="{Binding StreamDeck.SelectedKey.InputMode}" 
                ContentTemplateSelector="{StaticResource FromModeTemplateSelector}" />

2. 简化模板选择器逻辑

public class FromModeTemplateSelector : DataTemplateSelector
{
    public DataTemplate OpeningModeTemplate { get; set; } = new();
    public DataTemplate ShortcutModeTemplate { get; set; } = new();

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        return item switch
        {
            OpeningMode => OpeningModeTemplate,
            ShortcutMode => ShortcutModeTemplate,
            _ => base.SelectTemplate(item, container)
        };
    }
}

3. 调整模板内的绑定路径

此时模板的DataContext是InputMode实例,需要通过RelativeSource回溯到Window的DataContext(即MainViewModel):

<!-- 示例:修改ComboBox的绑定 -->
<ComboBox
    DockPanel.Dock="Top"
    ItemsSource="{Binding DataContext.StreamDeck.SelectedKey.ActionChoices, RelativeSource={RelativeSource AncestorType=Window}}"
    SelectedIndex="{Binding DataContext.StreamDeck.SelectedKey.SelectedActionIndex, RelativeSource={RelativeSource AncestorType=Window}}" />

方案2:手动触发模板重新选择

如果必须保持Content绑定到MainViewModel,可以通过监听InputMode的变更,强制ContentControl重新评估模板:

1. 在MainViewModel中添加触发属性

public InputModeBase TriggerTemplateRefresh => StreamDeck?.SelectedKey?.InputMode;

public MainViewModel()
{
    // 订阅SelectedKey的变更事件
    StreamDeck.PropertyChanged += (s, e) =>
    {
        if (e.PropertyName == nameof(StreamDeckViewModel.SelectedKey))
        {
            // 订阅新SelectedKey的InputMode变更事件
            StreamDeck.SelectedKey.PropertyChanged += SelectedKey_InputModeChanged;
            OnPropertyChanged(nameof(TriggerTemplateRefresh));
        }
    };
}

private void SelectedKey_InputModeChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == nameof(KeyViewModel.InputMode))
    {
        OnPropertyChanged(nameof(TriggerTemplateRefresh));
    }
}

2. 绑定触发属性并监听变更

<ContentControl x:Name="ModeContentControl"
                Content="{Binding}" 
                ContentTemplateSelector="{StaticResource FromModeTemplateSelector}"
                Tag="{Binding TriggerTemplateRefresh}" />

在MainWindow.xaml.cs中添加监听逻辑:

private void ModeContentControl_TagChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    var control = sender as ContentControl;
    control.ContentTemplate = control.ContentTemplateSelector.SelectTemplate(control.Content, control);
}

额外注意事项
  • 确保StreamDeckViewModel的SelectedKey属性在变更时触发PropertyChanged事件,否则切换不同Key时模板选择器也不会响应。
  • 使用CommunityToolkit.Mvvm的[ObservableProperty]特性可以简化属性实现,减少手动编写SetProperty的代码,降低出错概率。

内容的提问来源于stack exchange,提问作者Philipp Feldmann FV Feldmann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 00:07:05