MahApps.Metro WPF 开发使用过程中遇到的问题
-
- MainWindow.xaml
- MainWindow.xaml.cs
- 报错内容
- 解决方法:
-
- [方法一:【推荐】安装缺失的 NuGet 包](#方法一:【推荐】安装缺失的 NuGet 包)
- 方法二:【不推荐】尝试不使用它(并解释为什么不可行)
- 结论与最终建议
MainWindow.xaml
代码不是测试重点 重点是使用了 MahApps.Metro
csharp
<mah:MetroWindow
x:Class="gTools.ViewTests.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:gTools.ViewTests"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Grid>
<UniformGrid
Margin="5"
Columns="9"
Rows="9">
<!-- 手动添加81个按钮(实际开发建议用代码生成) -->
<Button
Margin="2"
Click="Button_MessageClick"
Content="弹窗测试" />
<Button
Margin="2"
Click="Button_GetTimeClick"
Content="获取时间" />
<!-- 省略其他79个按钮... -->
<Button Margin="2" Content="9-9" />
</UniformGrid>
</Grid>
</mah:MetroWindow>
MainWindow.xaml.cs
csharp
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : MetroWindow
{
public MainWindow()
{
InitializeComponent();
}
private async void Button_MessageClick(object sender, RoutedEventArgs e)
{
//// 在ViewModel中调用
//var messageService = new Message();
//await messageService.ShowAsync("保存成功");
//var result = await messageService.ShowCheckAsync("确认删除吗?");
//if (result == MessageDialogResult.Affirmative)
//{
// // 用户点击确定
//}
//// 显示警告气球提示
//messageService.ShowBalloonTipWarning("警告", "磁盘空间不足");
var msg = new Message();
msg.ShowBalloonTipWarning("警告", "磁盘空间不足"); // 气球提示
await msg.ShowAsync("操作成功完成"); // 简单提示
var result = await msg.ShowCheckAsync("确认删除吗?"); // 确认对话框
}
/// <summary>
/// 获取时间
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button_GetTimeClick(object sender, RoutedEventArgs e)
{
//var time = GetDateTime();
}
[DllImport("kernel32.dll")]
private static extern bool SetLocalTime(ref Systemtime time);
[StructLayout(LayoutKind.Sequential)]
private struct Systemtime
{
public short year;
public short month;
public short dayOfWeek;
public short day;
public short hour;
public short minute;
public short second;
public short milliseconds;
}
/// <summary>
/// 设置系统时间
/// </summary>
/// <param name="dt">需要设置的时间</param>
/// <returns>返回系统时间设置状态,true为成功,false为失败</returns>
public static bool SetLocalDateTime(DateTime dt)
{
Systemtime st;
st.year = (short)dt.Year;
st.month = (short)dt.Month;
st.dayOfWeek = (short)dt.DayOfWeek;
st.day = (short)dt.Day;
st.hour = (short)dt.Hour;
st.minute = (short)dt.Minute;
st.second = (short)dt.Second;
st.milliseconds = (short)dt.Millisecond;
bool rt = SetLocalTime(ref st);
return rt;
}
public static DateTime GetDateTime(long timeStamp)
{
return new DateTime(1970, 1, 1).AddSeconds(timeStamp).ToLocalTime();
}
public static bool GetInternetTime(string url, out DateTime dt, out string errMsg)
{
dt = DateTime.MinValue;
var startDt = DateTime.Now;
var port = 13;
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { ReceiveTimeout = 2000 };
try
{
var iphostinfo = Dns.GetHostEntry(url);
var ip = iphostinfo.AddressList[0];
var ipe = new IPEndPoint(ip, port);
var iar = socket.BeginConnect(ipe, null, null);
if (!iar.AsyncWaitHandle.WaitOne(5000))
{
errMsg = "连接超时" + url;
return false;
}
var recvBuffer = new byte[1024];
var sb = new StringBuilder();
var myE = Encoding.UTF8;
int nBytes;
while ((nBytes = socket.Receive(recvBuffer, 0, 1024, SocketFlags.None)) > 0)
{
sb.Append(myE.GetString(recvBuffer, 0, nBytes));
}
var o = sb.ToString().Split(' ');
TimeSpan ts = DateTime.Now - startDt;
var setDt = Convert.ToDateTime(o[1] + " " + o[2]).Subtract(-ts); // 减去中途消耗的时间
dt = setDt.ToLocalTime();
Console.WriteLine(@"服务器:{0}时间:{1}", url, setDt);
errMsg = "";
return true;
}
catch (Exception ex)
{
errMsg = ex.Message;
return false;
}
finally
{
socket.Close();
}
}
}
报错内容
FileNotFoundException: 未能加载文件或程序集"Microsoft.Xaml.Behaviors, Version=1.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"或它的某一个依赖项。系统找不到指定的文件。
System.Windows.Markup.XamlParseException:""对类型"gTools.ViewTests.MainWindow"的构造函数执行符合指定的绑定约束的调用时引发了异常。",行号为"8",行位置为"5"。"
解决方法:
当然可以不使用它!这个问题的本质是 MahApps.Metro 依赖 Microsoft.Xaml.Behaviors
,但你的项目里没有安装它 。
你有两个选择:
- 【推荐】解决依赖问题:安装缺失的 NuGet 包,一劳永逸。这是最简单、最标准的做法。
- 【不推荐】移除依赖源 :找到并移除 MahApps.Metro 中使用了
Behaviors
的功能,但这会破坏 UI 库的完整性,得不偿失。
下面我将详细解释这两种方法,并重点说明为什么推荐第一种。
方法一:【推荐】安装缺失的 NuGet 包
这就像汽车需要汽油才能跑一样。你的 UI 库(MahApps.Metro)需要 Microsoft.Xaml.Behaviors
这个"零件"才能正常工作。我们只需要把这个零件给它装上就行了。
操作步骤(非常简单):
- 在 Visual Studio 中,右键点击你的项目(
gTools.ViewTests
),选择 "管理 NuGet 程序包..."。 - 切换到 "浏览" 选项卡。
- 搜索
Microsoft.Xaml.Behaviors
。 - 点击 "安装" 。
安装完成后,重新运行项目,问题就解决了。
为什么这是最好的方法?
- 简单快捷:只需要点几下鼠标,无需修改任何代码。
- 官方标准:这是 .NET 生态管理依赖的标准方式。
- 功能完整:你可以继续使用 MahApps.Metro 的所有功能,不会有任何缺失。
- 面向未来:以后升级 MahApps.Metro 或其他库,也不容易出现类似问题。
方法二:【不推荐】尝试不使用它(并解释为什么不可行)
如果你坚持不想安装这个包,理论上就需要找到 MahApps.Metro 中哪个地方用到了它,然后禁用或修改它。但这几乎是不可能的,原因如下:
- 依赖是内部的 :
Behaviors
的使用是在 MahApps.Metro 的内部代码里,而不是在你的 XAML 或 C# 代码里。你无法通过修改自己的代码来避开它。 - 破坏库的完整性 :
Behaviors
通常用于实现一些复杂的交互效果,比如窗口拖拽、控件动画等。如果你强行移除依赖,可能会导致 MahApps.Metro 的某些核心功能直接崩溃或表现异常。 - 维护噩梦 :即使你通过修改 MahApps.Metro 源码的方式成功了(这非常复杂),那么以后每次 MahApps.Metro 更新,你都需要重新修改一遍,这将是一场灾难。
一个形象的比喻:
你买了一个需要安装电池的遥控器,但发现盒子里没有电池。现在遥控器用不了。
- 方法一(推荐):花几块钱买一节电池装上,遥控器就能正常用了。
- 方法二(不推荐):尝试拆开遥控器,修改它的内部电路,让它不依赖电池也能工作。这不仅需要极高的电子技术,而且很可能把遥控器彻底搞坏。
结论与最终建议
请选择方法一,安装 Microsoft.Xaml.Behaviors
NuGet 包。
这并不是一个"可选"的组件,而是 MahApps.Metro 正常工作的一个必需品 。你的项目缺少它,就像汽车没有油一样。安装它是解决这个问题的正确、唯一且最简单的途径。
不要因为一个看似"额外"的依赖而放弃使用一个强大的 UI 框架,或者走上修改源码的弯路。安装 NuGet 包是每个 .NET 开发者的日常操作,放心去做吧!