可扩展应用程序标记语言(XAML)是一种基于XML的声明式语言,用于在各种框架中初始化结构化值和对象。当问题是关于具有特定框架的XAML的使用时,还应该提供框架的标签,例如, [wpf](Windows Presentation Foundation),[silverlight],[windows-phone],[windows-store-apps](Windows 8商店应用),[win-universal-app],[xamarin.forms]或[工作流程 - 基础]
对于设置,我经常使用两列:用于标题/标签的 TextBlock 和用于值的 TextBox。它可以在 中完成,但我想让列对齐。 例如。 对于设置,我经常使用两列:用于标题/标签的 TextBlock 和用于值的 TextBox。它可以在 中完成,但我想让列对齐。 例如 <TextBlock Text="Server" Grid.Row="0"/> <TextBox Name="uiFtpServer" Grid.Row="0" Grid.Column="1"/> 我想为此创建用户控件。我差点就做到了:) Grid.Children 包含 TextBlock,但没有显示(Height=Width=0)。 <local:GridedTBox x:Name="uiFtpServer" Label="Server" Grid.Row="0"/> 和 Public Class GridedTBox Inherits TextBox ' making GridedTBox inherited from TextBox, I have all TextBox properties available on GridedTBox level Private _Label As New TextBlock Public Property Label As String Get Return _Label.Text End Get Set(value As String) _Label.Text = value End Set End Property Public Overrides Sub OnApplyTemplate() Dim gridek As Grid = TryCast(Me.VisualParent, Grid) If gridek Is Nothing Then Return gridek.Children.Add(_Label) ' _Label is added, but height=NaN, desiredsize=0,0, actualwidht=0, etc. If Grid.GetColumn(Me) > 0 Then Grid.SetColumn(_Label, Grid.GetColumn(Me) - 1) Else Grid.SetColumn(Me, 1) Grid.SetColumn(_Label, 0) End If _Label.ApplyTemplate() MyBase.OnApplyTemplate() ' still _Label has height=NaN, desiredsize=0,0, actualwidht=0, etc. ' now, debugging says that Grid.Columns has proper values (i.e. 1 for TextBox, 0 for TextBlock) ' but TextBox on screen is in column 0, so something changes it after this OnApplyTemplate End Sub End Class 问题:我做错了什么?我应该使用另一个事件处理程序吗? 您似乎在理解如何使用 UserControl 方面遇到了一些困难。我们来回顾一下整个过程: 1. CreateUserControl:您需要创建一个UserControl,然后实现您需要的任何内容。在您的情况下,我们需要一个 TextBox 的标签,我们需要为其动态分配名称,以及用于输入数据的文本框: LabelTBoxUserControl.xaml <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="20" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Path=Label, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> <TextBox Name="TextBoxUserControl" Grid.Row="0" Grid.Column="2" Width="{Binding Path=TextBoxWidth, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> </Grid> 在这段代码中,我们创建了具有三列的经典Grid(第二列是两个元素之间的空格,甚至可以动态分配,但目前还可以)。 Text 的 TextBlock 属性和 Width 的 TextBox 属性可以进行硬编码,但我们将解释如何动态地做到这一点。 2. 创建 DependencyProperties:简而言之,为 UserControls 创建自定义属性的正确方法是创建 DependencyProperties,然后将它们绑定到该属性。有关如何实现 DependencyProperties 的更多信息,您可以阅读:如何实现依赖属性(WPF .NET) LabelTBoxUserControl.xaml.cs public partial class LabelTBoxUserControl : UserControl { public LabelTBoxUserControl() { InitializeComponent(); } public string Label { get { return (string)GetValue(LabelProperty); } set { SetValue(LabelProperty, value); } } public static readonly DependencyProperty LabelProperty = DependencyProperty.Register("Label", typeof(string), typeof(LabelTBoxUserControl), new PropertyMetadata("Label")); public double TextBoxWidth { get { return (double)GetValue(TextBoxWidthProperty); } set { SetValue(TextBoxWidthProperty, value); } } public static readonly DependencyProperty TextBoxWidthProperty = DependencyProperty.Register("TextBoxWidth", typeof(double), typeof(LabelTBoxUserControl), new PropertyMetadata(1.0)); } 在 XAML 中,它是:{Binding Path=PropertyName, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}。这会在类型为 PropertyName 的父元素中搜索 UserControl。在我们的例子中,它将在 LabelTBoxUserControl 中查找。 3. 实现控件:只需为我们创建的属性赋值即可!您可以使用 DependencyProperties 执行很多操作来创建 UserControl。这是正确且最简单的方法,因为一旦您理解了 DependencyProperties,它们的使用就变得很简单。 MainWindow.xaml <Window x:Class="GenericProject.WPF.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:GenericProject.WPF" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <local:LabelTBoxUserControl Label="Server" TextBoxWidth="150"/> </Grid> </Window> 按照 DependencyProperties 中的定义,Label 的类型为 string,而 TextBoxWidth 的类型为 double(在这种情况下,WPF 会自动将 int 值转换为 double,不会出现任何问题) ).
在通用 Windows 应用程序中,我尝试使用背景图像(来自 ImageSource)并将其平铺在控件上。 XAML 在通用 Windows 应用程序中,我尝试使用背景图像(来自 ImageSource)并将其平铺到控件上。 XAML <Grid x:Name="gridBackground"> <ContentPresenter /> </Grid> C# void UpdateBackground(ImageSource source) { // ... gridBackground.Background = new ImageBrush { ImageSource = source, Stretch = Stretch.None }; } 根据MSDN,ImageBrush继承自TileBrush。它甚至说: 用于 ImageBrush,包括文本或平铺的装饰效果 控件或布局容器的背景。 我认为如果禁用拉伸,这应该平铺图像,但可惜,它只是在控件的中间绘制图像。我没有看到任何实际属性可以使其平铺。 在 WPF 中,有一个 TileMode 属性,可以设置 ViewPort 来指定图块的尺寸。但这在通用平台下似乎不存在。 上一个问题指的是WinRT(Windows 8),但我希望有一个基于画笔的解决方案,而不是用图像填充画布。 如何使用 UWP 平铺背景图像? 之前的问题涉及 WinRT (Windows 8),但我希望有一个基于画笔的解决方案,而不是用图像填充画布。 目前,在 UWP 应用中以平铺模式显示背景图像只有两种解决方案,您知道的第一个解决方案是填充画布。 我使用的第二个是创建一个Panel并在上面绘制图像,这个想法源自这篇文章 这种方法的作用是滥用我们在矩形中绘制重复的线条组这一事实。首先,它尝试在顶部绘制一个与我们的图块高度相同的块。然后它向下复制该块,直到到达底部。 我修改了一些代码并修复了一些问题: public class TiledBackground : Panel { public ImageSource BackgroundImage { get { return (ImageSource)GetValue(BackgroundImageProperty); } set { SetValue(BackgroundImageProperty, value); } } // Using a DependencyProperty as the backing store for BackgroundImage. This enables animation, styling, binding, etc... public static readonly DependencyProperty BackgroundImageProperty = DependencyProperty.Register("BackgroundImage", typeof(ImageSource), typeof(TiledBackground), new PropertyMetadata(null, BackgroundImageChanged)); private static void BackgroundImageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((TiledBackground)d).OnBackgroundImageChanged(); } private static void DesignDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((TiledBackground)d).OnDesignDataChanged(); } private ImageBrush backgroundImageBrush = null; private bool tileImageDataRebuildNeeded = true; private byte[] tileImagePixels = null; private int tileImageWidth = 0; private int tileImageHeight = 0; private readonly BitmapPixelFormat bitmapPixelFormat = BitmapPixelFormat.Bgra8; private readonly BitmapTransform bitmapTransform = new BitmapTransform(); private readonly BitmapAlphaMode bitmapAlphaMode = BitmapAlphaMode.Straight; private readonly ExifOrientationMode exifOrientationMode = ExifOrientationMode.IgnoreExifOrientation; private readonly ColorManagementMode coloManagementMode = ColorManagementMode.ColorManageToSRgb; public TiledBackground() { this.backgroundImageBrush = new ImageBrush(); this.Background = backgroundImageBrush; this.SizeChanged += TiledBackground_SizeChanged; } private async void TiledBackground_SizeChanged(object sender, SizeChangedEventArgs e) { await this.Render((int)e.NewSize.Width, (int)e.NewSize.Height); } private async void OnBackgroundImageChanged() { tileImageDataRebuildNeeded = true; await Render((int)this.ActualWidth, (int)this.ActualHeight); } private async void OnDesignDataChanged() { tileImageDataRebuildNeeded = true; await Render((int)this.ActualWidth, (int)this.ActualHeight); } private async Task RebuildTileImageData() { BitmapImage image = BackgroundImage as BitmapImage; if ((image != null) && (!DesignMode.DesignModeEnabled)) { string imgUri = image.UriSource.OriginalString; if (!imgUri.Contains("ms-appx:///")) { imgUri += "ms-appx:///"; } var imageSource = new Uri(imgUri); StorageFile storageFile = await StorageFile.GetFileFromApplicationUriAsync(imageSource); using (var imageStream = await storageFile.OpenAsync(FileAccessMode.Read)) { BitmapDecoder decoder = await BitmapDecoder.CreateAsync(imageStream); var pixelDataProvider = await decoder.GetPixelDataAsync(this.bitmapPixelFormat, this.bitmapAlphaMode, this.bitmapTransform, this.exifOrientationMode, this.coloManagementMode ); this.tileImagePixels = pixelDataProvider.DetachPixelData(); this.tileImageHeight = (int)decoder.PixelHeight; this.tileImageWidth = (int)decoder.PixelWidth; } } } private byte[] CreateBackgroud(int width, int height) { int bytesPerPixel = this.tileImagePixels.Length / (this.tileImageWidth * this.tileImageHeight); byte[] data = new byte[width * height * bytesPerPixel]; int y = 0; int fullTileInRowCount = width / tileImageWidth; int tileRowLength = tileImageWidth * bytesPerPixel; //Stage 1: Go line by line and create a block of our pattern //Stop when tile image height or required height is reached while ((y < height) && (y < tileImageHeight)) { int tileIndex = y * tileImageWidth * bytesPerPixel; int dataIndex = y * width * bytesPerPixel; //Copy the whole line from tile at once for (int i = 0; i < fullTileInRowCount; i++) { Array.Copy(tileImagePixels, tileIndex, data, dataIndex, tileRowLength); dataIndex += tileRowLength; } //Copy the rest - if there is any //Length will evaluate to 0 if all lines were copied without remainder Array.Copy(tileImagePixels, tileIndex, data, dataIndex, (width - fullTileInRowCount * tileImageWidth) * bytesPerPixel); y++; //Next line } //Stage 2: Now let's copy those whole blocks from top to bottom //If there is not enough space to copy the whole block, skip to stage 3 int rowLength = width * bytesPerPixel; int blockLength = this.tileImageHeight * rowLength; while (y <= (height - tileImageHeight)) { int dataBaseIndex = y * width * bytesPerPixel; Array.Copy(data, 0, data, dataBaseIndex, blockLength); y += tileImageHeight; } //Copy the rest line by line //Use previous lines as source for (int row = y; row < height; row++) Array.Copy(data, (row - tileImageHeight) * rowLength, data, row * rowLength, rowLength); return data; } private async Task Render(int width, int height) { Stopwatch fullsw = Stopwatch.StartNew(); if (tileImageDataRebuildNeeded) await RebuildTileImageData(); if ((height > 0) && (width > 0)) { using (var randomAccessStream = new InMemoryRandomAccessStream()) { Stopwatch sw = Stopwatch.StartNew(); var backgroundPixels = CreateBackgroud(width, height); sw.Stop(); Debug.WriteLine("Background generation finished: {0} ticks - {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds); BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, randomAccessStream); encoder.SetPixelData(this.bitmapPixelFormat, this.bitmapAlphaMode, (uint)width, (uint)height, 96, 96, backgroundPixels); await encoder.FlushAsync(); if (this.backgroundImageBrush.ImageSource == null) { BitmapImage bitmapImage = new BitmapImage(); randomAccessStream.Seek(0); bitmapImage.SetSource(randomAccessStream); this.backgroundImageBrush.ImageSource = bitmapImage; } else ((BitmapImage)this.backgroundImageBrush.ImageSource).SetSource(randomAccessStream); } } else this.backgroundImageBrush.ImageSource = null; fullsw.Stop(); Debug.WriteLine("Background rendering finished: {0} ticks - {1} ms", fullsw.ElapsedTicks, fullsw.ElapsedMilliseconds); } } 用途: <Grid x:Name="rootGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <tileCtrl:TiledBackground BackgroundImage="Assets/avatar1.png" Width="{Binding ActualWidth, ElementName=rootGrid}" Height="{Binding ActualHeight, ElementName=rootGrid}"/> </Grid> 查看解决方案 Github 所有这些变体对于 GPU 来说都很沉重。您应该使用 BorderEffect 通过 Composition API 来实现。 var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor; var canvasDevice = CanvasDevice.GetSharedDevice(); var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, canvasDevice); var bitmap = await CanvasBitmap.LoadAsync(canvasDevice, new Uri("ms-appx:///YourProject/Assets/texture.jpg")); var drawingSurface = graphicsDevice.CreateDrawingSurface(bitmap.Size, DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied); using (var ds = CanvasComposition.CreateDrawingSession(drawingSurface)) { ds.Clear(Colors.Transparent); ds.DrawImage(bitmap); } var surfaceBrush = compositor.CreateSurfaceBrush(drawingSurface); surfaceBrush.Stretch = CompositionStretch.None; var border = new BorderEffect { ExtendX = CanvasEdgeBehavior.Wrap, ExtendY = CanvasEdgeBehavior.Wrap, Source = new CompositionEffectSourceParameter("source") }; var fxFactory = compositor.CreateEffectFactory(border); var fxBrush = fxFactory.CreateBrush(); fxBrush.SetSourceParameter("source", surfaceBrush); var sprite = compositor.CreateSpriteVisual(); sprite.Size = new Vector2(1000000); sprite.Brush = fxBrush; ElementCompositionPreview.SetElementChildVisual(YourCanvas, sprite); 我尝试了 1000000x1000000 大小的精灵,并且毫不费力地工作了。 如果您的尺寸大于 16386px,Win2d 会抛出异常。 实际上,现在可以创建自定义画笔(借助 Composition API 和 Win2D)来实现平铺效果。代码示例在这里:UWP TiledBrush 简而言之,您只需子类化 XamlCompositionBrushBase 并重写它的 OnConnected 方法: public class TiledBrush : XamlCompositionBrushBase { protected override void OnConnected() { var surface = LoadedImageSurface.StartLoadFromUri(ImageSourceUri); var surfaceBrush = Compositor.CreateSurfaceBrush(surface); surfaceBrush.Stretch = CompositionStretch.None; var borderEffect = new BorderEffect() { Source = new CompositionEffectSourceParameter("source"), ExtendX = Microsoft.Graphics.Canvas.CanvasEdgeBehavior.Wrap, ExtendY = Microsoft.Graphics.Canvas.CanvasEdgeBehavior.Wrap }; var borderEffectFactory = Compositor.CreateEffectFactory(borderEffect); var borderEffectBrush = borderEffectFactory.CreateBrush(); borderEffectBrush.SetSourceParameter("source", surfaceBrush); } } 然后按预期使用它: <Grid> <Grid.Background> <local:TiledBrush ImageSourceUri="Assets/Texture.jpg" /> </Grid.Background> </Grid> 查看我对这个问题的回答: 您可以使用 Win2D 库进行平铺。他们也有示例代码; “效果”下有一个平铺示例(EffectsSample.xaml.cs)。 我们在 Windows 社区工具包中有 TilesBrush: <Border BorderBrush="Black" BorderThickness="1" VerticalAlignment="Center" HorizontalAlignment="Center" Width="400" Height="400"> <Border.Background> <brushes:TilesBrush TextureUri="ms-appx:///Assets/BrushAssets/TileTexture.png"/> </Border.Background> </Border> 我们还有 TileControl 允许动画。 评论从C#使用Win2d时必须注意内存泄漏。如果您想动态更改位图资源,还有一些微妙之处。 请参阅此问题的答案,了解这些问题的一种解决方案:在 WinUI 3 中重复画笔或图像平铺 WindowsCompositorSamples 中的“边框”示例也展示了如何执行此操作,以及旋转和缩放。 链接:https://github.com/microsoft/WindowsCompositionSamples/tree/master/SampleGallery/Samples/SDK%2015063/BorderPlayground 伙计们,TilesBrush 是更简单的选择。 需要 10 秒和一行代码。
WinUI:视图模型中的 PropertyChanged 处理程序为空
我有这个 win ui 主窗口,它分配一个视图模型并绑定到一个属性。文本最初从视图模型正确显示,但是当视图模型更新文本时,控件...
在另一个 LinearGradientBrush 中使用 LinearGradientBrush?
我正在尝试在另一个 LinearGradientBrush 的定义中使用一个 LinearGradientBrush。但我不知道这是否会起作用,如果它起作用,我需要知道如何做。 例如: <
嗨,我想构建一个简单的 xamarin.forms 应用程序,所以我在这里有 xaml 代码,所以在这段代码中我想添加网站 url,所以任何人都可以帮助我需要在 xaml 代码中添加哪些选项来添加
在我的应用程序的开发过程中,我发现许多页面的内容彼此非常相似,只有一处不同。为了防止重复代码,结果...
Visual Studio 22 - XAML 设计器无法为 WinUI 项目打开
无法在 XAML 设计器中打开任何 .xaml 文件 - 每当我尝试使用 XAML 设计器打开 XAML 文件时,它都会使用文本编辑器打开 我尝试过的: 确保工具 > 选项 >...
如果我的应用程序未设置 StartupUri,App.xaml 文件不会被解析?
背景:我正在使用 MVVM 创建一个 WPF 应用程序,并使用 DI 容器来构建我的 ViewModel 我的 App.xaml 如下所示: 背景:我正在使用 MVVM 创建 WPF 应用程序,并使用 DI 容器来构建我的 ViewModel 我的 App.xaml 看起来像这样: <Application x:Class="WpfApp.App" ...xmlns etc... StartupUri="MainWindow.xaml"> <Application.Resources> <app:ServiceLocator x:Key="serviceLocator" /> </Application.Resources> </Application> MainWindow.xaml 看起来像这样: <Window x:Class="CompositeMefWpfApp.MainWindow" ...xmlns etc... > <Control.DataContext> <Binding Path="MainWindowViewModel" Source="{StaticResource serviceLocator}" /> </Control.DataContext> 现在,这一切都工作正常,但是 StartupUri 被硬编码到 XAML 中,这是我不想要的。 根据我找到的几篇博文和文章的指导,我删除了 StartupUri,并尝试通过在 App.xaml.cs 中挂钩 MainWindow 来创建 OnStartup,如下所示: protected override void OnStartup( StartupEventArgs e ) { base.OnStartup(e); new MainWindow().Show(); } 问题是,应用程序在尝试显示窗口时崩溃,但以下例外: 找不到名为“{serviceLocator}”的资源。资源名称区分大小写。 标记文件“WpfApp;component/mainwindow.xaml”第 8 行位置 45 中的对象“System.Windows.Data.Binding”出错。 据我所知,<Application.Resources>部分根本没有从xaml文件中读出。我可以在 OnStartup 中添加一些代码,以编程方式添加资源,如下所示: Resources.BeginInit(); Resources.Add("serviceLocator", new ServiceLocator()); Resources.EndInit(); 然而,这是一个丑陋的黑客,如果我想稍后在 app.xaml 文件中添加其他内容,这对我没有帮助:-( 我应该挂钩其他活动吗?有办法解决这个问题吗? 不要重写 OnStartup,而是尝试使用事件: <Application x:Class="My.App" xmlns="..." Startup="Application_Startup" ShutdownMode="OnExplicitShutdown"> <Application.Resources> <app:ServiceLocator x:Key="serviceLocator" /> </Application.Resources> </Application> 背后代码: public partial class App : Application { public App() { } private void Application_Startup(object sender, StartupEventArgs e) { // TODO: Parse commandline arguments and other startup work new MainWindow().Show(); } } 最简单的解决方法是定义 x:Name: <Application x:Name="App" ... <Application.Resources> ... </Application.Resources> </Application> 更多信息:http://connect.microsoft.com/VisualStudio/feedback/details/472729/wpf-cannot-find-resource-define-in-the-app-xaml-file 我遇到了类似/相同的问题。 VS 代码生成存在一个错误,当 <Application.Resources> 仅包含一个条目并且没有 <Application.Resources> 属性时,有时不会插入将 StartupUri 连接到程序其余部分所需的代码。 详情: http://bengribaudo.com/blog/2010/08/19/106/bug-single-application-resources-entry-ignored (免责声明--链接指向我的博客) 要解决此已知错误,您还可以以编程方式添加资源。 var rd = new ResourceDictionary() rd.Source = new Uri("pack://application:,,,/Resources;component/Colors.xaml"); Resources.MergedDictionaries.Add(rd); 此代码可以放置在 App 类的构造函数中。 @Ben Gribaudo 提到有一个错误不允许 <Application.Resources> 正确连接。在他的博客中:http://bengribaudo.com/blog/2010/08/19/106/bug-single-application-resources-entry-ignored他提到了一个修复,您可以添加一个“虚拟”样式条目作为当仅定义一个条目时,该错误似乎会生效。 我在按钮样式的底部添加了<Style x:Key="unused because Application.Resources does not load if only one entry is defined." />,这达到了目的。
当方向=水平时,是什么让我的 VirtualizingStackPanel 无法虚拟化?
我有一个 ListView,我尝试用它来模拟 Windows 资源管理器的“列表”视图。为了显示这些项目,我使用了 S. Baeumlisberger 的 VirtualizingWrapPanel,它会水平滚动并
所以我看到 XML 命名空间的通常标准是 xmlns:"clr-命名空间:My.Package;程序集=Some.Assembly" 然而,最近在另一个 SO 答案中,我看到有人将其替换为 xmlns:“usi...
类似于聚焦时的 UWP 文本框背景 我正在尝试为我的应用程序中的 Focused TextBox 元素设置一些应用程序范围的样式指南。我的问题是我想申请不同...
我应该在 MAUI 中使用哪种 StackLayout 类型?
就我使用 MAUI 而言,我只使用过 和 来水平或垂直定位子元素。 我很少或漂亮...
在我的 .NET MAUI 应用程序中,我想在 XAML 中格式化日期/时间,以显示工作日短名称和日期。例如,日期 24.11.2024 应这样显示(使用德语工作日
我有一个由单个窗口 MainWindow.xaml 组成的 WPF 应用程序 标题为 Sample_Window 我有一个 WPF application 由一个窗口组成 MainWindow.xaml 带有标题 Sample_Window <Window Title="Sample_Window"> <Grid> <Frame x:Name="mainFrame" Source="/Page1.xaml" /> <Grid> </Window> 和三页: Page1.xaml Page2.xaml Page3.xaml 我的问题是我想更改每个页面导航上的主窗口标题 例如,当我降落到 Page1.xaml 时,标题应该是 Sample_Window-Page1 等。 我在XAML中尝试了下面的代码:(不起作用) <Page WindowTitle="Sample_Window-Page1" Title="Page1"> </Page> 另外,在CS中:(不起作用) Page1 mypage= new Page1(); mypage.WindowTitle="Sample_Window-Page1"; 我也经历过这个问题如何为WPF页面提供标题 但没有解决我的问题。标题仍然与 Sample_Window 相同 如果您的 Page1 标题是动态生成的(“Customer Joe Smith Details”),您可能在 Page1ViewModel 上有一个名为 Title 的属性。在这种情况下,您可以简单地从主窗口绑定到框架的内容的 DataContext: <Window Title="{Binding ElementName=mainFrame, Path=Content.DataContext.Title}"> <Grid> <Frame x:Name="mainFrame" Source="/Page1.xaml" /> </Grid> </Window> 如果您的 Page1 标题是静态文本(使用 Title 而不是 WindowTitle 属性),则只需从主窗口直接绑定到它: <Window Title="{Binding ElementName=mainFrame, Path=Content.Title}"> <Grid> <Frame x:Name="mainFrame" Source="/Page1.xaml" /> </Grid> </Window> 上面的内容对我不起作用,因为它在运行应用程序时加载了 [myPage1]。 我通过单击 MainWindow 上的按钮显示 [myPage1],以便显示带有静态标题的页面,我将所需的标题文本添加到导航中。 主窗口.xaml <DockPanel> <Frame x:Name="_mainFrame"/> </DockPanel> button_click方法中的MainWindow.xaml.cs _mainFrame.NavigationService.Navigate(new [myPage1] (Title= "what ever you want displayed")); protected override void OnContentChanged(object oldContent, object newContent) { base.OnContentChanged(oldContent, newContent); this.Title = newContent is not Page page || string.IsNullOrWhiteSpace(page.Title) ? this.ViewModel.Title : page.Title; } 我到目前为止使用这个没有任何问题。如果没有导航到页面,它有一个后备。您可能可能想更改视图模型,但是您还需要单独存储默认标题。使其与框架一起使用可能也不太难。 this.Title = "Sample_Window-Page1"; 你能试试这个吗?框架不会更改窗口,因此标题会保留,您应该在每次页面更改时更新窗口标题。
我在当前的 WPF 项目中使用 MVVM Light,我想知道什么时候应该使用 MVVM Light 的消息传递而不是 WPF 事件。 WPF 事件: 我的控件.xaml 我在当前的 WPF 项目中使用 MVVM Light,我想知道什么时候应该使用 MVVM Light 的消息传递而不是 WPF 事件。 WPF 事件: MyControl.xaml <ListView SelectionChanged="ListView_OnSelectionChanged" /> MyControl.cs private MyViewModel ViewModel { get { return this.DataContext as MyViewModel; } } private void ListView_OnSelectionChanged( object sender, SelectionChangedEventArgs e ) { this.ViewModel.ListViewSelectionChanged( ( (ListView) sender ).SelectedItems ); } MVVM 轻消息传递: MyControl.cs private void ListView_OnSelectionChanged( object sender, SelectionChangedEventArgs e ) { Messenger.Default.Send( new ListViewSelectionMessage {SelectedItems = ((ListView)sender).SelectedItems} ); } ListViewSelectionMessage.cs public class ListViewSelectionMessage { public IList SelectedItems { get; set; } } 我的视图模型 public class MyViewModel { MyViewModel() { Messenger.Default.Register<ListViewSelectionMessage>(this, this.ListViewSelectionChaged); } private void ListViewSelectionChaged( ListViewSelectionMessage message ) { // ... } } 因为使用 Messenger,一切都可以很容易地解耦,所以我很想在任何地方都使用 Messenger。使用 Messenger 而不是 Events 有什么问题吗?或者这会产生我不知道的问题。谢谢! 通常,任何 MVVM 框架(Prism、MVVM Light)中的消息都是在具有插件架构的应用程序中的松散耦合组件之间进行通信的好方法,因为您可以通过共享库中声明的合约将消息从一个模块发送到另一个模块。当您单独开发应用程序或在小团队中由高技能程序员开发应用程序时,可以使用它。 否则有一个主要缺点:重构和调试非常困难,因为你不能只点击消息并“查找用法”,你需要先去合约(接口)而不是“查找用法”,然后直观地查找带有订阅/注册指令的地方。此外,开发人员通常会忘记取消订阅消息,因此您将面临问题,即从一个模块发送并打算在同一模块中处理的消息将在其他模块中错误地处理,因此会导致意外行为并产生许多令人痛苦的错误。 以上内容均基于我的个人经验,因此结果可能会有所不同。只要小心消息,它就会对你有好处。另外,在我看来,消息作为事件的替代品有点开销/过度设计,因为当您拥有紧密耦合的组件时,您并不真正需要它。 2024 年更新,随着 MVVMLight 被弃用,MVVM Toolkit(其精神继承者)具有 Messenger 类:https://learn.microsoft.com/dotnet/communitytoolkit/mvvm/messenger 性能基准:https://devblogs.microsoft.com/dotnet/announcing-the-dotnet-community-toolkit-800/#improved-messenger-apis-📬
如何解决 .NET MAUI 中 WebView 和 ScrollView 内 CarouselView 的间距问题?
(https://i.sstatic.net/mXYjWeDs.png) 我正在构建一个 .NET MAUI 应用程序,它显示具有以下功能的文章: 从右向左或从左向右滑动可在文章之间移动。 滚动你...
如何使用 XAML 将 TextBlock 绑定到内部字段?
我有一个基本 DataClass,其中包含字符串形式的日期信息。 公共类数据类 { 字符串日期信息; } 我有一个 UserControl,其中包含该类的一个实例和一个 TextBlock。 ...
无法在 .Net 9 应用程序中引用 WinUI 3 社区工具包
大项目正在将UWP应用程序转换为WinUI3。 UWP 应用使用 UWP Toolkit 作为网格拆分器控件。 尝试在 WINUI + .Net 9 中引用 CommunityToolkit 我可以选择 Nuget Package