gpt4 book ai didi

c# - 只读依赖属性更新但在首次使用时不起作用

转载 作者:行者123 更新时间:2023-11-30 22:57:03 26 4
gpt4 key购买 nike

我正在尝试创建一些 WPF 用户控件以包含在库中以与我的团队共享,但是只读属性对我的工作方式有问题。

对于这个问题,我做了一个非常简单的用户控件,它有两个 DependencyProperties。一个基于 enum,另一个基于选定的 enum 执行操作。 enum 用于选择按钮将使用的样式。

该应用程序是一个常规的 Wpf 应用程序,带有一个 Wpf 用户控件库作为引用。我怀疑控件库可能导致了这个问题,所以我觉得它与示例相关。

Wpf 控件库1

Dictionary1.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfControlLibrary1">
<Style x:Key="SampleStyle-Font1">
<Setter Property="TextElement.FontFamily" Value="Wingdings" />
<Setter Property="TextElement.FontSize" Value="30" />
</Style>
<Style x:Key="SampleStyle-Font2">
<Setter Property="TextElement.FontFamily" Value="Elephant" />
<Setter Property="TextElement.FontSize" Value="30" />
</Style>
<Style x:Key="SampleStyle-Font3">
<Setter Property="TextElement.FontFamily" Value="Times New Roman" />
<Setter Property="TextElement.FontSize" Value="30" />
</Style>
</ResourceDictionary>

用户控件1.xaml:

<UserControl x:Class="WpfControlLibrary1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfControlLibrary1"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="200">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.Template>
<ControlTemplate>
<Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:UserControl1}}, Path=Command}">
<StackPanel>
<Label Style="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:UserControl1}}, Path=ReadOnlyStyle}" Content="{Binding Path=Content, RelativeSource={x:Static RelativeSource.TemplatedParent}}"></Label>
</StackPanel>
</Button>
</ControlTemplate>
</UserControl.Template>
</UserControl>

UserControl1.xaml.cs

namespace WpfControlLibrary1 {
using System.Windows;
using System.Windows.Controls;

/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl {
public enum StyleSelector {
Style1,
Style2,
Style3
}

public static DependencyProperty SelectedStyleProperty =
DependencyProperty.Register("SelectedStyle", typeof(StyleSelector), typeof(UserControl1), new PropertyMetadata(ReadOnlyStyle_Changed));

private static readonly DependencyPropertyKey ReadOnlyStylePropertyKey =
DependencyProperty.RegisterReadOnly("ReadOnlyStyle", typeof(Style),
typeof(UserControl1), null);

public UserControl1() {
InitializeComponent();
}

public StyleSelector SelectedStyle {
get => (StyleSelector)GetValue(SelectedStyleProperty);
set => SetValue(SelectedStyleProperty, value);
}

public Style ReadOnlyStyle => (Style)GetValue(ReadOnlyStylePropertyKey.DependencyProperty);

private static void ReadOnlyStyle_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) {
if (!(d is UserControl1 userControl1)) {
return;
}

Style style;
switch (userControl1.SelectedStyle) {
case StyleSelector.Style1:
style = (Style)userControl1.FindResource("SampleStyle-Font1");
break;
case StyleSelector.Style2:
style = (Style)userControl1.FindResource("SampleStyle-Font2");
break;
case StyleSelector.Style3:
style = (Style)userControl1.FindResource("SampleStyle-Font3");
break;
default:
style = (Style)userControl1.FindResource("SampleStyle-Font1");
break;
}

userControl1.SetValue(ReadOnlyStylePropertyKey, style);
}
}
}

Wpf 应用程序

主窗口.xaml:

<Window x:Class="ReadOnlyDependencyPropertiesWithUserControls.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:ReadOnlyDependencyPropertiesWithUserControls"
xmlns:wpfControlLibrary1="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"
mc:Ignorable="d"
Title="Example" Height="200" Width="400">
<StackPanel>
<wpfControlLibrary1:UserControl1 SelectedStyle="Style1" Content="This is the first control"></wpfControlLibrary1:UserControl1>
<wpfControlLibrary1:UserControl1 SelectedStyle="Style2" Content="This is the second control"></wpfControlLibrary1:UserControl1>
<wpfControlLibrary1:UserControl1 SelectedStyle="Style3" Content="This is the third control"></wpfControlLibrary1:UserControl1>
</StackPanel>
</Window>

下面的输出显示第一个控件显示样式。如果我运行该应用程序,使用 Live 编辑器将其切换到 Style2,然后返回到 Style1,WingDings 字体会接管,但在重新运行时它不会。这看起来确实像是一个依赖属性问题,但据我所知我的设置是正确的,尤其是因为其他两个控件似乎可以正常工作。

The first control should use the WingDings font, but does not

最佳答案

诊断

它不起作用的原因是因为您在 SelectedStyle 属性更改处理程序中分配了 ReadOnlyStyle 属性值。由于 SelectedStyle 属于 StyleSelector 类型,它是一个 enum,并且您没有明确为此属性分配默认值,它将具有默认值default(StyleSelector) 由框架分配,恰好是 StyleSelector.Style1。即使您在第一个控件上将该值显式分配给此属性,该值也不会真正改变,因此不会调用处理程序,因此 ReadOnlyStyle 仍然是 null,因此,你得到你得到的(一个具有默认样式的 Label)。

解决方案

为了解决这个问题,您应该为 ReadOnlyStyle 分配初始值。但是由于样式保存在资源字典中,您不能在构造函数中执行此操作。分配初始值的一个好点是:

protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
var style = (Style)userControl1.FindResource("SampleStyle-Font1");
SetValue(ReadOnlyStylePropertyKey, style);
}

更好的解决方案

实现目标的“WPF 方式”是使用触发器。所以首先你可以从你的控件中删除不必要的代码:

public partial class UserControl1 : UserControl
{
public enum StyleSelector
{
Style1,
Style2,
Style3
}

public static DependencyProperty SelectedStyleProperty =
DependencyProperty.Register("SelectedStyle", typeof(StyleSelector), typeof(UserControl1));

public UserControl1()
{
InitializeComponent();
}

public StyleSelector SelectedStyle
{
get => (StyleSelector)GetValue(SelectedStyleProperty);
set => SetValue(SelectedStyleProperty, value);
}
}

然后修改你的模板:

<ControlTemplate>
<Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:UserControl1}}, Path=Command}">
<StackPanel>
<Label x:Name="PART_Label" Content="{Binding Path=Content, RelativeSource={x:Static RelativeSource.TemplatedParent}}" />
</StackPanel>
</Button>
<ControlTemplate.Triggers>
<Trigger Property="local:UserControl1.SelectedStyle" Value="Style1">
<Setter TargetName="PART_Label" Property="Style" Value="{StaticResource SampleStyle-Font1}" />
</Trigger>
<Trigger Property="local:UserControl1.SelectedStyle" Value="Style2">
<Setter TargetName="PART_Label" Property="Style" Value="{StaticResource SampleStyle-Font2}" />
</Trigger>
<Trigger Property="local:UserControl1.SelectedStyle" Value="Style3">
<Setter TargetName="PART_Label" Property="Style" Value="{StaticResource SampleStyle-Font3}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

这里有两件重要的事情:

  1. Label 需要有 x:Name 以便在 Setter.TargetName 中引用它
  2. Trigger.Property 值需要完全限定,因为 ControlTemplate 没有设置 TargetType

关于c# - 只读依赖属性更新但在首次使用时不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53887412/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com