当MainWindow为null时如何设置DataContext?无Window类直接启动UserControl
如何在WPF中通过StartupUri启动UserControl时设置DataContext?
嘿,这个问题我之前也碰到过!核心原因是WPF的StartupUri如果指向的是UserControl,它会自动创建一个默认的Window来承载它,但这个Window不会立刻被赋值给app.MainWindow——至少在你调用Run()前是拿不到的。结合你的代码,给你几个可行的解决办法:
先贴一下你的原始代码方便对照:
class Program : Application { [STAThread] public static void Main() { Program app = new Program(); app.StartupUri = new Uri("../../LoginWindow.xaml", UriKind.Relative); //app.MainWindow is null app.Run(); } virtual protected void OnStartUp(StartupEventArgs e) { MessageBox.Show("Start up"); } }
方法1:给UserControl套一个Window(最稳妥的标准做法)
WPF的StartupUri设计初衷就是用来启动Window类型的,所以最直接的方式是新建一个极简的Window来承载你的LoginWindow UserControl,这样app.MainWindow就能正常指向这个Window,设置DataContext就很简单了:
- 新建
LoginHostWindow.xaml:
<Window x:Class="YourProjectNamespace.LoginHostWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:YourProjectNamespace" Title="登录" WindowStartupLocation="CenterScreen" SizeToContent="WidthAndHeight" BorderThickness="0"> <!-- 直接把UserControl作为Window的内容 --> <local:LoginWindow /> </Window>
- 修改
Main方法,同时设置DataContext:
[STAThread] public static void Main() { Program app = new Program(); app.StartupUri = new Uri("LoginHostWindow.xaml", UriKind.Relative); // 等Window加载完成后给内部的UserControl设置DataContext app.MainWindow.Loaded += (sender, e) => { var loginViewModel = new YourLoginViewModel(); // 替换成你的ViewModel实例 (app.MainWindow.Content as LoginWindow).DataContext = loginViewModel; }; app.Run(); }
方法2:利用Application的Startup事件获取承载Window
如果不想额外新增Window,可以借助Application.Startup事件——当应用启动完成后,WPF已经把UserControl加载到默认Window里了,这时候就能拿到MainWindow并找到内部的UserControl:
另外注意:你的代码里把OnStartup拼成了OnStartUp(大小写错误),WPF的虚方法是OnStartup,写错的话不会被框架触发哦,下面是修正后的代码:
class Program : Application { [STAThread] public static void Main() { Program app = new Program(); app.StartupUri = new Uri("../../LoginWindow.xaml", UriKind.Relative); app.Run(); } // 修正拼写:OnStartup(不是OnStartUp) protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); // 此时MainWindow已经被赋值为承载UserControl的默认窗口 if (MainWindow?.Content is LoginWindow loginControl) { loginControl.DataContext = new YourLoginViewModel(); // 设置你的ViewModel } MessageBox.Show("Start up"); } }
方法3:直接在UserControl内部设置DataContext(最简单的场景)
如果你的ViewModel不需要依赖Main方法里的任何参数,完全可以直接在LoginWindow.xaml中声明DataContext,一步到位:
<UserControl x:Class="YourProjectNamespace.LoginWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:YourProjectNamespace"> <UserControl.DataContext> <!-- 直接实例化ViewModel --> <local:YourLoginViewModel /> </UserControl.DataContext> <!-- 你的UserControl内容 --> </UserControl>
内容的提问来源于stack exchange,提问作者霜月幻夜
相关产品推荐
相关产品推荐

