为什么我可以更改在 Windows.Resources 而不是 Application.Resources 定义的资源属性
Why I can change a resource properties when it defined at Windows.Resources but not from Application.Resources
问题:
我注意到如果我在我的 Windows.Resources
中定义相同的资源,当我以 TwoWay
模式绑定到它们时,我可以对其属性进行一些更改,但如果我在 Application.Resources
。我对 Static/Dynamic 资源有所了解,我认为这两个地方都应该是静态的!
问题:
当我们在 Windows.Resources
级别定义资源时,为什么我们可以对资源进行一些更改?在Windows.Resources
中定义时是否初始化为DynamicResource
?还是有其他原因!?
附带问题:当我们在 Application.Resources
中定义它时,有没有办法让它工作?
要检查的代码
在 Windows 级别定义一个资源并绑定到它并更改它的 属性 没有任何问题:
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<SolidColorBrush x:Key="MyBrush" Color="GreenYellow"/>
</Window.Resources>
<StackPanel>
<Button Background="{StaticResource MyBrush}" Content="Button 1" Margin="10"/>
<Button Background="{StaticResource MyBrush}" Content="Button 2" Margin="10"/>
<Slider Value="{Binding Source={StaticResource MyBrush}, Path=Opacity, Mode=TwoWay}"
Maximum="1" TickFrequency="0.01"/>
</StackPanel>
</Window>
但是如果我像这样将资源定义移动到 Application.Resources
中:
<Application x:Class="WpfApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
StartupUri="MainWindow.xaml">
<Application.Resources>
<SolidColorBrush x:Key="MyBrush" Color="GreenYellow"/>
</Application.Resources>
</Application>
我在输出中得到这个异常 window:
System.Windows.Data Error: 8 : Cannot save value from target back to source. BindingExpression:Path=Opacity; DataItem='SolidColorBrush' (HashCode=37320431); target element is 'Slider' (Name=''); target property is 'Value' (type 'Double') InvalidOperationException:'System.InvalidOperationException: Cannot set a property on object '#FFADFF2F' because it is in a read-only state.
我认为这是正确的回答,因为上面的资源被定义为静态的。我试过这个技巧来解决上面的问题:
<Slider DataContext="{DynamicResource MyBrush}" Value="{Binding Path=Opacity, Mode=TwoWay}"
Maximum="1" TickFrequency="0.01"/>
运气不好!我的主要问题仍然是为什么当我们在 Windows.Resources
!?
使用资源时它的行为不同
搜索到现在才找到答案
我读了这些,但没有我要找的答案:
Changing SolidColorBrush#Color in resource dictionary failed: Property is readonly [duplicate]
一个SolidColorBrush
is a type derived from Freezable
,看它的继承链。
Object > DispatcherObject > DependencyObject > Freezable > Animatable > Brush > SolidColorBrush
A Freezable
是一种可以在运行时冻结的特殊类型,这使得它不可修改。
Defines an object that has a modifiable state and a read-only (frozen) state. Classes that derive from Freezable provide detailed change notification, can be made immutable, and can clone themselves.
InvalidOperationException
表明 SolidColorBrush
已经被冻结。
To make a Freezable unmodifiable, you call its Freeze
method. When you freeze an object that contains freezable objects, those objects are frozen as well. [...]
Once you call a freezable's Freeze method, it can no longer be modified. Attempting to modify a frozen object causes an InvalidOperationException
to be thrown.
根据这个MSDN forum post,应用程序资源总是自动冻结。
-> Are Resources which are defined in the Application.Resources always frozen.
This is a by design side effect.
事实上,查看 ResourceDictionary
的参考源,您可以看到如果通过 Add
方法或索引器添加资源,则会调用 SealValue
method。评论说明了一切。
This method
Sets the InheritanceContext of the value to the dictionary's principal owner
Seals the freezable/style/template that is to be placed in an App/Theme/Style/Template ResourceDictionary
因此,您的 SolidColorBrush
和任何其他可冻结对象在应用程序资源字典中自动冻结。这是设计使然,我想这可能是由于性能原因。
A Freezable provides a Changed event to notify observers of any modifications to the object. Freezing a Freezable can improve its performance, because it no longer needs to spend resources on change notifications. A frozen Freezable can also be shared across threads, while an unfrozen Freezable cannot.
作为对参考源的旁注:所有实现 ISealable
的类型都被密封在那里。在 documentation, there is no notion of Freezable
implementing ISealable
, but according to its reference source it does and it explicitly implements the Seal
方法中只需调用 Freeze
.
关于您对静态和动态资源的理解,资源既不是定义为静态的也不是动态的,它们只是资源。 StaticResource
and DynamicResource
只是定义您如何引用资源的标记扩展,这意味着它的 查找行为 .
有没有办法让你想要的行为与应用程序资源字典一起工作?我不这么认为,因为即使在合并的资源字典中,代码也会显式地冻结资源,所以定义一个单独的资源字典是行不通的,PresentationOptions:Freeze="False"
也行不通。因此,在不同的范围内定义资源似乎是唯一的选择。
问题:
我注意到如果我在我的 Windows.Resources
中定义相同的资源,当我以 TwoWay
模式绑定到它们时,我可以对其属性进行一些更改,但如果我在 Application.Resources
。我对 Static/Dynamic 资源有所了解,我认为这两个地方都应该是静态的!
问题:
当我们在 Windows.Resources
级别定义资源时,为什么我们可以对资源进行一些更改?在Windows.Resources
中定义时是否初始化为DynamicResource
?还是有其他原因!?
附带问题:当我们在 Application.Resources
中定义它时,有没有办法让它工作?
要检查的代码
在 Windows 级别定义一个资源并绑定到它并更改它的 属性 没有任何问题:
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<SolidColorBrush x:Key="MyBrush" Color="GreenYellow"/>
</Window.Resources>
<StackPanel>
<Button Background="{StaticResource MyBrush}" Content="Button 1" Margin="10"/>
<Button Background="{StaticResource MyBrush}" Content="Button 2" Margin="10"/>
<Slider Value="{Binding Source={StaticResource MyBrush}, Path=Opacity, Mode=TwoWay}"
Maximum="1" TickFrequency="0.01"/>
</StackPanel>
</Window>
但是如果我像这样将资源定义移动到 Application.Resources
中:
<Application x:Class="WpfApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
StartupUri="MainWindow.xaml">
<Application.Resources>
<SolidColorBrush x:Key="MyBrush" Color="GreenYellow"/>
</Application.Resources>
</Application>
我在输出中得到这个异常 window:
System.Windows.Data Error: 8 : Cannot save value from target back to source. BindingExpression:Path=Opacity; DataItem='SolidColorBrush' (HashCode=37320431); target element is 'Slider' (Name=''); target property is 'Value' (type 'Double') InvalidOperationException:'System.InvalidOperationException: Cannot set a property on object '#FFADFF2F' because it is in a read-only state.
我认为这是正确的回答,因为上面的资源被定义为静态的。我试过这个技巧来解决上面的问题:
<Slider DataContext="{DynamicResource MyBrush}" Value="{Binding Path=Opacity, Mode=TwoWay}"
Maximum="1" TickFrequency="0.01"/>
运气不好!我的主要问题仍然是为什么当我们在 Windows.Resources
!?
搜索到现在才找到答案
我读了这些,但没有我要找的答案:
Changing SolidColorBrush#Color in resource dictionary failed: Property is readonly [duplicate]
一个SolidColorBrush
is a type derived from Freezable
,看它的继承链。
Object > DispatcherObject > DependencyObject > Freezable > Animatable > Brush > SolidColorBrush
A Freezable
是一种可以在运行时冻结的特殊类型,这使得它不可修改。
Defines an object that has a modifiable state and a read-only (frozen) state. Classes that derive from Freezable provide detailed change notification, can be made immutable, and can clone themselves.
InvalidOperationException
表明 SolidColorBrush
已经被冻结。
To make a Freezable unmodifiable, you call its
Freeze
method. When you freeze an object that contains freezable objects, those objects are frozen as well. [...] Once you call a freezable's Freeze method, it can no longer be modified. Attempting to modify a frozen object causes anInvalidOperationException
to be thrown.
根据这个MSDN forum post,应用程序资源总是自动冻结。
-> Are Resources which are defined in the Application.Resources always frozen.
This is a by design side effect.
事实上,查看 ResourceDictionary
的参考源,您可以看到如果通过 Add
方法或索引器添加资源,则会调用 SealValue
method。评论说明了一切。
This method
Sets the InheritanceContext of the value to the dictionary's principal owner
Seals the freezable/style/template that is to be placed in an App/Theme/Style/Template ResourceDictionary
因此,您的 SolidColorBrush
和任何其他可冻结对象在应用程序资源字典中自动冻结。这是设计使然,我想这可能是由于性能原因。
A Freezable provides a Changed event to notify observers of any modifications to the object. Freezing a Freezable can improve its performance, because it no longer needs to spend resources on change notifications. A frozen Freezable can also be shared across threads, while an unfrozen Freezable cannot.
作为对参考源的旁注:所有实现 ISealable
的类型都被密封在那里。在 documentation, there is no notion of Freezable
implementing ISealable
, but according to its reference source it does and it explicitly implements the Seal
方法中只需调用 Freeze
.
关于您对静态和动态资源的理解,资源既不是定义为静态的也不是动态的,它们只是资源。 StaticResource
and DynamicResource
只是定义您如何引用资源的标记扩展,这意味着它的 查找行为 .
有没有办法让你想要的行为与应用程序资源字典一起工作?我不这么认为,因为即使在合并的资源字典中,代码也会显式地冻结资源,所以定义一个单独的资源字典是行不通的,PresentationOptions:Freeze="False"
也行不通。因此,在不同的范围内定义资源似乎是唯一的选择。