提供哈希表/字典实现,其包含WPF应用程序的组件和其他元素使用的WPF资源(例如,矢量绘图,画笔,颜色,控件模板,数据模板等)。
应用自定义样式时 Silverlight 4 + PRISM 中出现错误
情况: 带有 App.xaml 的“Shell”项目和 Styles/Default.xaml 中的资源字典,其中有趣的部分如下: 默认.xmal 情况: “Shell”项目,包含 App.xaml 和 Styles/Default.xaml 中的资源字典,其中包含有趣的部分: 默认.xmal <ResourceDictionary <Style x:Key="StandardTextBox" TargetType="TextBox"> ... </Style> </ResourceDictionary 应用程序.xaml <Application> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Styles/Default.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application> 在模块项目中,我有一个表单: <TextBox Style="{StaticResource StandardTextBox}" /> 在运行时,我收到臭名昭著的“错误 HRESULT E_FAIL 已从对 COM 组件的调用返回”。例外。 有趣的是,在设计时,在VS中,样式在设计模式下应用得很好。 (VS.Net 如何发挥神奇作用,知道 Shell 项目中的 App.xaml 中有一个资源(模块项目根本没有引用该资源)令人费解……但我离题了) 我的总体目标是在 Shell 项目中与 App.xaml 分开的文件中定义资源,并在模块项目中本质上应用样式。 真正的问题是不包括另一个引用的样式。请参阅这个。
我有一个简单的组合框模板,其结构如下: 我有一个以这种方式构造的组合框的简单模板: <ComboBox DockPanel.Dock="Left" MinWidth="100" MaxHeight="24" ItemsSource="{Binding Actions}"> <ComboBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}" Width="100" /> <Image Source="{Binding Converter={StaticResource TypeConverter}}" /> </StackPanel> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox> 所以,如果我使用这段代码,一切都会正常: <TextBlock Text="{Binding Name}" Width="100" /> <!--<Image Source="{Binding Converter={StaticResource TypeConverter}}" /> --> <Image Source="{StaticResource SecurityImage}" /> 但是如果我使用转换器,它就不再起作用了。 这是转换器,但我不知道如何从那里引用静态资源... public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var type = (Action)value; var img = new BitmapImage(); switch (type.ActionType) { case ActionType.Security: img.UriSource = new Uri("StructureImage", UriKind.Relative); break; case ActionType.Structural: img.UriSource = new Uri("SecurityImage", UriKind.Relative); break; } return img; } 尝试使用 Josh 编写的 Switch Converter,应该对你有用: SwitchConverter – XAML 的“switch 语句”- http://josheinstein.com/blog/index.php/2010/06/switchconverter-a-switch-statement-for-xaml/ 无需编写转换器,您的代码将如下所示 - <Grid.Resources> <e:SwitchConverter x:Key="ActionIcons"> <e:SwitchCase When="Security" Then="SecurithImage.png" /> <e:SwitchCase When="Structural" Then="StructureImage.png" /> </e:SwitchConverter> </Grid.Resources> <Image Source="{Binding Converter={StaticResource ActionIcons}}" /> 更新1: 这是 SwitchConverter 的代码,因为 Josh 的 网站似乎已关闭 - /// <summary> /// A converter that accepts <see cref="SwitchConverterCase"/>s and converts them to the /// Then property of the case. /// </summary> [ContentProperty("Cases")] public class SwitchConverter : IValueConverter { // Converter instances. List<SwitchConverterCase> _cases; #region Public Properties. /// <summary> /// Gets or sets an array of <see cref="SwitchConverterCase"/>s that this converter can use to produde values from. /// </summary> public List<SwitchConverterCase> Cases { get { return _cases; } set { _cases = value; } } #endregion #region Construction. /// <summary> /// Initializes a new instance of the <see cref="SwitchConverter"/> class. /// </summary> public SwitchConverter() { // Create the cases array. _cases = new List<SwitchConverterCase>(); } #endregion /// <summary> /// Converts a value. /// </summary> /// <param name="value">The value produced by the binding source.</param> /// <param name="targetType">The type of the binding target property.</param> /// <param name="parameter">The converter parameter to use.</param> /// <param name="culture">The culture to use in the converter.</param> /// <returns> /// A converted value. If the method returns null, the valid null value is used. /// </returns> public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { // This will be the results of the operation. object results = null; // I'm only willing to convert SwitchConverterCases in this converter and no nulls! if (value == null) throw new ArgumentNullException("value"); // I need to find out if the case that matches this value actually exists in this converters cases collection. if (_cases != null && _cases.Count > 0) for (int i = 0; i < _cases.Count; i++) { // Get a reference to this case. SwitchConverterCase targetCase = _cases[i]; // Check to see if the value is the cases When parameter. if (value == targetCase || value.ToString().ToUpper() == targetCase.When.ToString().ToUpper()) { // We've got what we want, the results can now be set to the Then property // of the case we're on. results = targetCase.Then; // All done, get out of the loop. break; } } // return the results. return results; } /// <summary> /// Converts a value. /// </summary> /// <param name="value">The value that is produced by the binding target.</param> /// <param name="targetType">The type to convert to.</param> /// <param name="parameter">The converter parameter to use.</param> /// <param name="culture">The culture to use in the converter.</param> /// <returns> /// A converted value. If the method returns null, the valid null value is used. /// </returns> public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } /// <summary> /// Represents a case for a switch converter. /// </summary> [ContentProperty("Then")] public class SwitchConverterCase { // case instances. string _when; object _then; #region Public Properties. /// <summary> /// Gets or sets the condition of the case. /// </summary> public string When { get { return _when; } set { _when = value; } } /// <summary> /// Gets or sets the results of this case when run through a <see cref="SwitchConverter"/> /// </summary> public object Then { get { return _then; } set { _then = value; } } #endregion #region Construction. /// <summary> /// Switches the converter. /// </summary> public SwitchConverterCase() { } /// <summary> /// Initializes a new instance of the <see cref="SwitchConverterCase"/> class. /// </summary> /// <param name="when">The condition of the case.</param> /// <param name="then">The results of this case when run through a <see cref="SwitchConverter"/>.</param> public SwitchConverterCase(string when, object then) { // Hook up the instances. this._then = then; this._when = when; } #endregion /// <summary> /// Returns a <see cref="System.String"/> that represents this instance. /// </summary> /// <returns> /// A <see cref="System.String"/> that represents this instance. /// </returns> public override string ToString() { return string.Format("When={0}; Then={1}", When.ToString(), Then.ToString()); } } 更新2: 来自 Microsoft 参考源的另一个 SwitchConverter 实现。 使用Image.UriSource时,如果图像已添加到您的项目中并且其“构建操作”已设置为“资源”,则需要指定图像的相对文件路径。 例如。如果您已将图像放在 Visual Studio 中名为“images”的项目文件夹中,则可以通过以下方式引用图像: img.UriSource = new Uri("/Images/StructureImage.png", UriKind.Relative); 如果图像未构建为资源,则必须使用完整文件路径,即 img.UriSource = new Uri("http://server/Images/StructureImage.png", UriKind.Absolute); 编辑: 如果您将图像放入应用程序资源字典中,您始终可以通过以下方式访问它: Application.Current.Resources["StructureImage"]; 如果您将资源放在其他地方,您可以使用 IMultiValueConverter 而不是 IValueConverter 作为转换器。 那么你的类型转换器将如下所示: class TestValueConverter : IMultiValueConverter { #region IMultiValueConverter Members public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { // Validation of parameters goes here... var type = (Action) values[0]; var image1 = values[1]; var image2 = values[2]; if (type.ActionType == ActionType.Security) { return image1; } else { return image2; } } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion } 您的 XAML 看起来与此类似: <Image> <Image.Source> <MultiBinding Converter="{StaticResource testValueConverter}"> <Binding Path="Action" /> <Binding Source="{StaticResource SecurityImage}" /> <Binding Source="{StaticResource StructureImage}" /> </MultiBinding> </Image.Source> </Image> 最后,这就是您定义资源的方式: <imaging:BitmapImage x:Key="StructureImage" UriSource="StructureImage.png" /> <imaging:BitmapImage x:Key="SecurityImage" UriSource="SecurityImage.png" /> <local:TestValueConverter x:Key="testValueConverter" /> 以上代码未经测试! 虽然接受的答案很好,但我通常会避免“组合框”中带有图像的转换器的复杂性。我通常将图像源 (uri) 的数据类型定义为字符串。这样,就不需要转换器了。下面是一个分步示例: 第1步:创建语言对象类 public class Language { public int Id { get; set; } public string Code { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; public string Uri { get; set; } = string.Empty; } 第 2 步:在视图模型或隐藏代码中创建语言对象的数组 public class ExampleViewModel { private ObservableCollection<Language>? _languages; public IEnumerable<Language>? Languages => _languages; public ExampleViewModel() { string baseUri = "pack://application:,,,/;component/Images"; // The following static data can also come from the database _languages = [ new() { Id = 2, Code = "en-GB", Name = "English", Uri = $"{baseUri}/gb.png" }, new() { Id = 1, Code = "de-DE", Name = "German", Uri = $"{baseUri}/de.png" } ]; } } 第3步:在视图中创建组合框 XAML: <ComboBox x:Name="cbxLanguageSelection" Margin="0,0,0,0" HorizontalAlignment="Left" Background="Transparent" BorderThickness="0" ItemsSource="{Binding Languages}" SelectedItem="{Binding SelectedLanguage, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource ResourceKey=ComboBoxStyle}" ToolTip="Language Selection" Visibility="Visible"> <ComboBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Style="{StaticResource ResourceKey=DropDownStyle}"> <Image Height="18" Margin="0,0,5,0" Source="{Binding Path=Uri}" /> <TextBlock Text="{Binding Path=Name}" /> </StackPanel> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox> *)请注意,样式和“SelectedLanguage”是可选的。 “SelectedLanguage”属性应在实现时在视图模型或代码隐藏中创建。
我有一个包含两个数据模板的资源字典。每个模板都有一个带有对象的堆栈面板。 根据我从其他地方获得的条件,在我的代码后面,我想嵌入其中之一
我创建了一个类库,其中包含 WPF Windows 和一些从我的 C# 类继承的用户控件,这些控件帮助我自定义某些 WPF 控件。 现在我想添加 ResourceDictionar...
共享ControlTemplate.两个按钮样式之间的触发器
请提供一点帮助...我有这个 ResourceDictionary 来设置按钮的样式。有一个“基本按钮样式”,现在我正在开发一个按钮,该按钮将有一个下拉内容菜单,其中
在我的字典文件中我有 <Setter Property="Foreground" Value="White" /> <Setter Property="</desc> <question vote="7"> <p>在我的字典文件中</p> <pre><code><Style TargetType="{x:Type Label}" BasedOn="{StaticResource {x:Type Label}}"> <Setter Property="Foreground" Value="White" /> <Setter Property="Background" Value="Black" /> </Style> </code></pre> <p>在我的 Window xaml 文件中</p> <pre><code> <Window.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="pack://application:,,,/XXX;component/XXX.xaml"/> </ResourceDictionary.MergedDictionaries> <Style TargetType="Label" BasedOn="{StaticResource {x:Type Label}}"> <Setter Property="FontSize" Value="20"/> <Setter Property="VerticalAlignment" Value="Center"/> </Style> </ResourceDictionary> </Window.Resources> </code></pre> <p>在设计器中,我可以看到标签具有黑色背景和白色前景,但在运行时它具有默认的黑色前景和透明背景。很明显,我想继承字典样式,但它不起作用。我在那里做错了什么吗?我正在使用 VS 2013 和 .NET 4.5</p> <p>编辑: 如果我删除 Windows.Resources 中的样式,则将应用字典样式。如果我将样式从 Windows 资源移动到包含一些标签的 StackPanel.Resource,那么继承工作正常</p> </question> <answer tick="true" vote="6"> <p>根据 MSDN,<a href="http://msdn.microsoft.com/en-us/library/aa350178%28v=vs.110%29.aspx" rel="nofollow">合并资源字典</a>:</p> <p><pre><code>If a key is defined in the primary dictionary and also in a dictionary that was merged, then the resource that is returned will come from the primary dictionary.</code></pre></p> <p>根据这个规则,首先找到你的第二种风格。然后该样式引用具有相同 <pre><code>{x:Type Label}</code></pre> 键的样式。由于某种原因,结果是 <pre><code>null</code></pre>。然而,检查第一个样式表明它的 BasedOn 引用已解析为默认的 Label 样式,正如预期的那样。当两种样式被赋予相同的显式键时,也会发生同样的情况。然而,当给他们不同的密钥时,一切都会按预期进行。</p> <p>我的猜测是第二种风格掩盖了第一种风格。也许 BasedOn 引用已解析为样式本身,但为了防止循环依赖,它被设置为 null。</p> <p>我个人会使用显式键。对于需要应用于某种类型的所有元素,但在某些情况下仍需要覆盖的样式,我会将其分为两种样式:</p> <pre><code>// The actual style, with all its setters, is given a descriptive name: <Style x:Key="DescriptiveName" TargetType="Label" BasedOn="{StaticResource {x:Type Label}}"> // Setters go here </Style> // A 'dummy' style that references the above style. // Its sole purpose is to apply the style to all elements of the target type. <Style TargetType="Label" BasedOn="{StaticResource DescriptiveName}" /> </code></pre> <p>当您需要覆盖样式时,您可以通过其名称明确引用它:</p> <pre><code><Style TargetType="Label" BasedOn="{StaticResource DescriptiveName}"> // Overriding setters go here </Style> </code></pre> </answer> <answer tick="false" vote="0"> <p>我只是想找到解决方案,但我找到了一种不同的方法。</p> <p>根据 MSDN <a href="https://learn.microsoft.com/en-us/dotnet/desktop/wpf/systems/xaml-resources-merged-dictionaries?view=netdesktop-8.0" rel="nofollow noreferrer">合并词典</a></p> <blockquote> <p>尽管资源键在任何单个字典中都必须是唯一的,但一个键可以在一组合并字典中存在多次。在这种情况下,返回的资源将来自 MergedDictionaries 集合中按顺序找到的最后一个字典。</p> </blockquote> <p>所以我决定根本不把密钥放在App.xaml中。相反,我仅将要覆盖的项目放入合并文件中。我的解决方案:</p> <p>应用程序.xaml</p> <pre><code><Application x:Class="WPF_NET_CORE_8_Starter.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WPF_NET_CORE_8_Starter" Startup="OnStartup"> <Application.Resources> <!-- cannot override --> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="DarkOrange" /> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" /> <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="DarkOrange" /> </Application.Resources> </Application> </code></pre> <p>UIDefault.xaml(键=BackgroundBrush)</p> <pre><code><ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <LinearGradientBrush x:Key="BackgroundBrush" EndPoint="1,0.5" StartPoint="0,0.5"> <GradientStop Color="#FF454545" Offset="0" /> <GradientStop Color="#FFC1B9B9" Offset="1" /> </LinearGradientBrush> </ResourceDictionary> </code></pre> <p>UIChanged.xaml(相同的关键渐变颜色反转)</p> <pre><code><ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <LinearGradientBrush x:Key="BackgroundBrush" EndPoint="1,0.5" StartPoint="0,0.5"> <GradientStop Color="#FFC1C1C1" Offset="0" /> <GradientStop Color="#FF454545" Offset="1" /> </LinearGradientBrush> </ResourceDictionary> </code></pre> <p>MainWindow.xaml(相当精简)</p> <pre><code> <Window.Background> <StaticResource ResourceKey="BackgroundBrush" /> </Window.Background> </code></pre> <p>应用程序.xaml.cs</p> <pre><code>private void ConfigureUI() { ResourceDictionary uIdefault = []; uIdefault.Source = new Uri("UIDefault.xaml", UriKind.Relative); Application.Current.Resources.MergedDictionaries.Add(uIdefault); if (someCondition) { ResourceDictionary dictChanged = []; dictChanged.Source = new Uri("UIChange.xaml", UriKind.Relative); Application.Current.Resources.MergedDictionaries.Add(dictChanged); } } private void OnStartup(object sender, StartupEventArgs e) { ConfigureUI(); MainWindow? mainWindow = _serviceProvider.GetService<MainWindow>(); if (mainWindow != null) WindowHelper.OpenWindow(mainWindow); } </code></pre> <p>所以还有另一种选择。到目前为止,我还没有尝试过样式,只是尝试了一种资源。我敢打赌它适用于任何由键定义的东西。</p> <p>迈克</p> </answer> </body></html>
我基于 DataGrid 构建了一个 UserControl,以便添加我没有详细说明的过滤功能。它相当复杂,但效果很好(稍后我必须弄清楚如何删除大量隐藏代码)。 我...
从 WPFapplication 创建的可运行 Dll 找不到引用的 ResourceDictionary
我现在搜索了一段时间,没有找到针对具体问题的解决方案。 首先,我开发了一个 WPF 应用程序,其中包含多个项目和用户控件,在更多...
我想在我的应用程序中拥有多个资源字典并访问特定资源字典中定义的资源。这可能吗?根据我读到的内容,正在寻找
当我选择一个元素时,我需要更改它的样式。 资源字典: <Setter Property="StrokeShape" ...</desc> <question vote="0"> <p>当我选择一个元素时,我需要更改它的样式。 资源词典:</p> <pre><code><Style TargetType="Border" x:Key="СBorder"> <Setter Property="StrokeShape" Value="RoundRectangle 8" /> <Setter Property="Stroke" Value="#D9D9D9"> </Setter> <Setter Property="StrokeThickness" Value="1"></Setter> </Style> <Style TargetType="Border" x:Key="SelectBorder"> <Setter Property="StrokeShape" Value="RoundRectangle 8" /> <Setter Property="Stroke" Value="#9B6CFF"> </Setter> <Setter Property="StrokeThickness" Value="2"></Setter> </Style> </code></pre> <p>Xaml代码:</p> <pre><code><VerticalStackLayout Spacing="15" Margin="0,20,0,0"> <Border Style="{StaticResource СBorder}" x:Name="LoginBorder"> <Entry Style="{StaticResource CEntry}" Placeholder="E-mail" x:Name="LoginEntry" Completed="LoginEntry_Completed" TextChanged="LoginEntry_TextChanged" ></Entry> </Border> <Border Style="{StaticResource SelectBorder}" x:Name="PasswordBorder"> <Entry Style="{StaticResource CEntry}" Placeholder="Пароль" Completed="PasswordEntry_Completed" TextChanged="LoginEntry_TextChanged" x:Name="PasswordEntry" IsPassword="True"></Entry> </Border> <Button WidthRequest="307" HeightRequest="46" Text="Вход" Style="{StaticResource CButton}"> </Button> </VerticalStackLayout> </code></pre> <p>我尝试使用<pre><code>LoginBorder.Style = (Style)Application.Current.Resources["SelectBorder"];</code></pre>,但导致错误<pre><code>System.Collections.Generic.KeyNotFoundException: 'The resource 'SelectBorder' is not present in the dictionary.'</code></pre>,在网上搜索后,我找不到解决方案。</p> </question> <answer tick="false" vote="0"> <p>您可以使用<a href="https://learn.microsoft.com/en-us/dotnet/maui/user-interface/visual-states?view=net-maui-8.0" rel="nofollow noreferrer">视觉状态</a>:</p> <pre><code><VerticalStackLayout Margin="0,20,0,0" Spacing="15"> <Border x:Name="LoginBorder"> <VisualStateManager.VisualStateGroups> <VisualStateGroupList> <VisualStateGroup Name="CommonStates"> <VisualState Name="Normal"> <VisualState.Setters> <Setter Property="StrokeShape" Value="RoundRectangle 8" /> <Setter Property="Stroke" Value="#D9D9D9" /> <Setter Property="StrokeThickness" Value="1" /> </VisualState.Setters> </VisualState> <VisualState Name="Focused"> <VisualState.Setters> <Setter Property="StrokeShape" Value="RoundRectangle 8" /> <Setter Property="Stroke" Value="#9B6CFF" /> <Setter Property="StrokeThickness" Value="2" /> </VisualState.Setters> </VisualState> <VisualState Name="Disabled"> <VisualState.Setters> <Setter Property="BackgroundColor" Value="DarkGray" /> </VisualState.Setters> </VisualState> <VisualState Name="PointerOver"> <VisualState.Setters> <Setter Property="BackgroundColor" Value="LightBlue" /> </VisualState.Setters> </VisualState> </VisualStateGroup> <VisualStateGroupList> </VisualStateManager.VisualStateGroups> <Entry x:Name="LoginEntry" Placeholder="E-mail" /> </Border> <Border x:Name="PasswordBorder"> <Entry x:Name="PasswordEntry" IsPassword="True" Placeholder="Пароль" /> </Border> <Button HeightRequest="46" Text="Вход" WidthRequest="307" /> </VerticalStackLayout> </code></pre> </answer> </body></html>
我试图在 Common.xaml 中定义一个公共宽度资源,它将由不同的控件共享,如下所示: 20 然后我用它...
Javascript & React - 如何在不使用字典/对象的情况下避免“如果地狱”?
我知道这个问题以前曾被问过,但通常的答案给我带来了另一个(潜在的)问题和疑问。 上下文 我有一个函数,它返回必须撕裂的组件...
Maui App.xaml 基于平板电脑或手机的“OnIdiom”在两个 ResourceDictionary 文件之间加载
我有两个资源字典,一个用于移动设备,一个用于平板电脑,我想使用 OnIdiom 将正确的资源字典合并到 App.xaml 中。 使用 OnPlatform 很简单,但我不明白...
我需要帮助来创建我正在运行的代码的替代方案。非常感谢您的回答、支持和同行评审。 这个答案对我帮助很大。我的按钮形状确实符合我的预期。我的目标...
我的基础程序集包含一些 xaml 资源,这些资源由依赖于此基础 dll 的程序集上的某些自定义 WPF UserControl 使用,为此,我正在使用 我的基础程序集包含一些 xaml 资源,这些资源由依赖于此基础 dll 的程序集上的某些自定义 WPF UserControl 使用,为此,我正在使用 <ResourceDictionary Source="pack://application,,,/assemblyname;component/Resources.xaml"/> 我需要以不同的名称编译这个基础 dll。 由于程序集名称正在更改,因此上面的 URI 在其他 dll 上会被破坏。我想使用条件编译来更改程序集名称,因此我尝试将资源字典的定义移动到后面的代码中,执行类似的操作 ResourceDictionary res = new(); res.Source=new Uri("/assemblyname;component/Resources.xaml", UriKind.Relative); this.Resources.MergedDictionaries.Add(res); 这个想法是将这段代码封装在 #if ... #endif 中,其中程序集的名称将根据编译配置而更改。 我没有成功。有人可以提供实现此动态资源的选项吗?谢谢 一个有效的解决方案是最终在 App.xaml.cs 中加载资源,因此将我的问题后面的代码从控件的构造函数移动到 App.xaml.cs ,它在运行时解决了问题,但随后控件在设计时不太好。我使用以下方法找到了问题的解决方案:将 uri 移动到静态成员,这样问题就可以在运行时和设计时解决了
我有两个资源文件(资源字典) Brushes.xaml:包含一些画笔 Templates.xaml :包含一些静态引用(StaticResource)Brushes.xaml 中的键的模板 ...
是否可以在另一个用户控件中使用我在中定义的资源,而无需使用资源字典的额外文件。 我有一个用户控件“ViewCostumers&
动态解析 MergedDictionaries 中的静态资源
对所有代码感到抱歉,但我觉得我需要它来解释问题。另外,我知道一些问题可以通过使用动态资源来解决,但我也需要它来处理静态资源......
动态解析 MergedDictionaries 中的静态资源
对所有代码感到抱歉,但我觉得我需要它来解释问题。另外,我知道一些问题可以通过使用动态资源来解决,但我也需要它来处理静态资源......
我正在尝试为 MAUI 的初始设置创建 C# 实用程序,以确保设置过程不会分散在 5 个文件中。为此,我需要将以下内容转换为 C# 代码: 我正在尝试为 MAUI 的初始设置创建 C# 实用程序,以确保设置过程不会分散在 5 个文件中。为此,我需要将以下内容转换为 C# 代码: <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Resources/Styles/Colors.xaml" /> <ResourceDictionary Source="Resources/Styles/Styles.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> 到目前为止我已经尝试了两种方法: var converter = new ResourceDictionary.RDSourceTypeConverter(); try { var c = converter.ConvertFromString(resourcepath); } catch (Exception ex) { // thrown not implemented exception } resourceDictionary.MergedDictionaries.Add(new() { Source = new Uri(resourcepath, UriKind.Relative) // throws exception saying I need to use XAML }); 有没有其他方法可以创建不影响性能的资源字典? 您绝对可以实例化一个 ResourceDictionary 并将其动态添加到应用程序资源的 MergedDictionaries。 但是,这通常可以在某些地方起作用(从我自己的存储库之一中的 App.xaml.cs 文件中获取和修改): if (Current?.Resources.MergedDictionaries is not { } mergedDictionaries) { return; } mergedDictionaries.Clear(); mergedDictionaries.Add(new global::Resources.Styles.Colors()); mergedDictionaries.Add(new global::Resources.Styles.Styles()); 请注意,这些资源字典是编译的。您不能仅将它们作为路径来引用。不过,我不知道这是否真的比默认方式更快。 更新 为此,您需要更新 Colors.xaml 和 Styles.xaml 仅 XAML 资源字典,并使用 x:Class 属性为它们指定类名称: <?xml version="1.0" encoding="UTF-8" ?> <?xaml-comp compile="true" ?> <ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Resources.Styles.Colors"> </ResourceDictionary> 然后您可以使用 new global::Resources.Styles.Colors() 和 new global::Resources.Styles.Styles() 实例化它们。 更新2 如果您提供 x:Name 的 ResourceDictionary 一个完全限定的名称(例如 MyProject.Resources.Styles.Colors),然后在不使用 global:: 的情况下实例化它,则可能也有效,如下所示: mergedDictionaries.Add(new Resources.Styles.Colors()); 进一步阅读 官方文档还展示了如何动态添加资源字典(用于为应用程序主题化,但原理是相同的):https://learn.microsoft.com/en-us/dotnet/maui/user-interface/theming ?view=net-maui-7.0#在运行时加载主题 对于那些希望在 MAUI 中使用资源字典而不使用 xaml 页面(仅 C#)的人,这就是我让它工作的方式。 注意:我的项目中唯一的 xaml 页面是默认的 Resources\Styles\Styles.xaml 和 Resources\Styles\Colors.xaml 为 xaml 资源页面创建代码隐藏文件。 namespace MyApp.Resources.Styles; public partial class Styles : ResourceDictionary { public Styles() { InitializeComponent(); } } 然后修改xaml从 <?xml version="1.0" encoding="UTF-8" ?> <?xaml-comp compile="true" ?> <-- REMOVE THIS SO THE CODE-BEHIND FILE WILL COMPLIE <ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"> 到 <?xml version="1.0" encoding="UTF-8" ?> <ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyApp.Resources.Styles.Styles"> <-- ADD FULLY QUALIFIED CLASS NAME 然后添加 App.cs 构造函数(按照 Julian 建议) if (Application.Current?.Resources.MergedDictionaries is not { } mergedDictionaries) { return; } mergedDictionaries.Clear(); mergedDictionaries.Add(new Resources.Styles.Colors()); mergedDictionaries.Add(new Resources.Styles.Styles()); 在 C# 页面构造函数中使用(例如:MainPage.cs) Application.Current.Resources.TryGetValue("BtnStyle", out object btnStyle); 然后到控件 new Button { Text = "Click Me", Style = (Style)btnStyle as Style, } 请记住向 xaml 资源定义中定义的任何样式添加 x:Key。 文件样式.xaml <Style x:Key="BtnStyle" TargetType="Button"> <Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Primary}}" /> ************* OMITTED SETTERS *************** </Setter> </Style>