WPF 将窗口标题绑定到 ViewModel 属性

Posted

技术标签:

【中文标题】WPF 将窗口标题绑定到 ViewModel 属性【英文标题】:WPF Bind Window Title to ViewModel Property 【发布时间】:2013-06-05 16:30:00 【问题描述】:

我正在尝试将 Window Title 绑定到具有 Title 属性的 ViewModel。下面是 MainWindow XAML:

<Window x:Class="MyProject.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:MyProject.ViewModel;assembly=MyProject.ViewModel"
        Title="Binding Path=Title" Height="350" Width="525" DataContext="Binding Source=StaticResource mainWindowViewModel">
    <Window.Resources>
        <vm:MainWindow x:Key="mainWindowViewModel"/>
    </Window.Resources>

...

</Window>

当我尝试运行它时,我得到以下异常“在 'System.Windows.StaticResourceExtension' 上提供值引发异常。行号和位置指向 DataContext 属性,内部异常状态为“找不到资源命名为 mainWindowViewModel。

下面是视图模型的代码:

namespace MyProject.ViewModel

    public class MainWindow : INotifyPropertyChanged
    
        #region Fields

        private const string TitlebarPrefixString = "My Project";
        private string title = TitlebarPrefixString;

        public string Title 
            get
            
                return this.title;
             // End getter
            set
                
                this.title = value;
                OnPropertyChanged("Title");
             // End setter
         // End property

        protected virtual void OnPropertyChanged(string propertyName)
        
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            
                handler(this, new PropertyChangedEventArgs(propertyName));
             // End if
         // End method


        public event PropertyChangedEventHandler PropertyChanged;

     // End class
 // End namespace

我的理论是在尝试将标题绑定到属性之后加载资源。抛出异常时,Window 的 Resources 属性为空。

是唯一的解决方案是在后面的代码中设置 DataContext 吗?我可以让它工作,但我更愿意将它保存在 XAML 中。

【问题讨论】:

如果适用,您始终可以将您的 VM 资源移动到 app.xaml。在旁注中,请将 VM 类命名为 SomethingViewModel,而不仅仅是与 View 相同的名称,并使用命名空间来区分类。这真的很奇怪和怪异 Josh Smith 有一个这样的例子,我会看看我能不能找到它,基本上当在 XAML 中应用数据模板时,标题也被应用了.. 【参考方案1】:

您可以尝试使用属性元素语法设置DataContext

<Window x:Class="MyProject.View.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:MyProject.ViewModel;assembly=MyProject.ViewModel"
    Title="Binding Path=Title" Height="350" Width="525">
<Window.Resources>
    <vm:MainWindow x:Key="mainWindowViewModel"/>
</Window.Resources>
<Window.DataContext>
  <StaticResourceExtension ResourceKey="mainWindowViewModel"/>
</Window.DataContext>

这应该可以工作,因为 xaml 解析器将在设置资源字典后执行 StaticResourceExtension

但我认为直接设置 DataContext 而不将其声明为资源可能更好:

<Window x:Class="MyProject.View.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:MyProject.ViewModel;assembly=MyProject.ViewModel"
    Title="Binding Path=Title" Height="350" Width="525">
<Window.DataContext>
    <vm:MainWindow x:Key="mainWindowViewModel"/>
</Window.DataContext>

【讨论】:

您的第一个建议引发了同样的异常。有趣的是,当我使用 Break 时,Window 会在 Locals 视图中显示资源。第二个建议给出了三个编译时错误:““Key”属性只能用于 IDictionary 中包含的元素”; “Key 属性只能用于 IDictionary 类型属性中包含的标记”和“Key 属性只能用于字典中包含的标记(例如 ResourceDictionary” @Tim 我在 ResourceKey="mainWindowModel".. 中犯了一个错误。它应该声明 ResourceKey="mainWindowViewModel" 。如果您只是复制粘贴,请尝试更正它。但我不太确定这一点,我想一旦我让它像那样工作。 修复了它,这真是个好消息。我正在重新审视这个问题,因为我在引用以编程方式声明的视图模型时遇到了困难,因此再次将其设为纯 XAML 可能会帮助我解决其他问题。 @jure 你的建议帮助我解决了一个相关的问题。我想将窗口标题设置为带有路径和转换器的绑定。我在&lt;Window.Resources&gt; 中定义了转换器,但是在&lt;Window&gt; 中设置绑定会引发异常,因为它还没有访问&lt;Window.Resources&gt; 的权限。按照您建议的方式设置窗口标题是一种简单的解决方法。谢谢。【参考方案2】:

有点晚了,但我正在使用一个简单而完美的解决方案,以防人们仍在寻找可能性:

<Window x:Class="Project.MainWindow"
        Title="Binding DataContext.ApplicationTitle, ElementName=TheMainView">

        <views:MainView x:Name="TheMainView"/>

</Window>

很简单,只需向您的 MainViewModel 添加一个属性,即 MainView 的 DataContext,如下所示:

public string ApplicationTitle
        
            get
            
                var text = "Application Name";
                if (!string.IsNullOrEmpty(_currentFileLoaded))
                
                    text += $" (_currentFileLoaded)";
                

                return text;
            
        

希望对你有帮助..

【讨论】:

以上是关于WPF 将窗口标题绑定到 ViewModel 属性的主要内容,如果未能解决你的问题,请参考以下文章

将 WPF xaml 绑定到 ViewModel 而不构造它

WPF 绑定到父 DataContext

WPF 在 MVVM 模式下实现窗口后台代码与ViewModel交互

父属性更改时嵌套属性的 WPF 绑定更新通知

将WPF DatePicker绑定到字符串属性[重复]

WPF MVVM 从 ViewModel 触发事件的正确方法