c# - WPF - 将面板切换到编辑模式,但使用样式排除特定部分
问题描述
我在应用程序中使用的面板有许多不同的部分。当按下按钮时,我想将面板/画布/用户控件等的某些部分置于编辑模式,而我可以根据我创建的附加属性排除其他部分。在我的 ViewModel 中,我使用了一个布尔属性“IsEnabled”,我在该属性上绑定了一个全局样式(编辑:在本示例中为文本框在资源字典中定义),如下所示:
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEnabled}" Value="False">
<Setter Property="Properties:Properties.Editable" Value="False"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsEnabled}" Value="True">
<Setter Property="Properties:Properties.Editable" Value="True"/>
</DataTrigger>
<Trigger Property="Properties:Properties.Editable" Value="False">
<Setter Property="Background" Value="Red"/> //For visibility to see if its working
<Setter Property="IsReadOnly" Value="True"/>
</Trigger>
<Trigger Property="Properties:Properties.Editable" Value="True">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="IsReadOnly" Value="False"/>
</Trigger>
</Style.Triggers>
</Style>
附加属性定义为:
static Properties()
{
EditableProperty = DependencyProperty.RegisterAttached("Editable", typeof(bool), typeof(EasyProperties), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));
}
public static readonly DependencyProperty EditableProperty;
public static void SetEditable(DependencyObject dependencyObject, bool value)
{
dependencyObject.SetValue(EditableProperty, value);
}
public static bool GetEditable(DependencyObject dependencyObject)
{
return (bool)dependencyObject.GetValue(EditableProperty);
}
一个示例 XAML 看起来像这样,我想通过将容器中的可编辑属性设置为 false 来排除堆栈面板下的用户控件的一部分:
<ScrollViewer Padding="5,5,5,5" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid x:Name="_MainGrid" Background="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}" MinWidth="400">
<Grid.RowDefinitions>
<RowDefinition Height="5"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox x Width="40" Text="Test" Grid.Row="1"/>
<StackPanel Properties:Properties.Editable="False" Grid.Column="2" Grid.Row="1">
<TextBox Width="40" Text="Test" Grid.Column="2" Grid.Row="1"/>
<TextBox Width="40" Text="Test" Grid.Column="2" Grid.Row="1"/>
</StackPanel>
</Grid>
</Stackpanel>
我期望会发生什么:
从 ViewModel 的 isEnabled 属性开始,设置为“true”-> 因此所有控件都应该是可编辑的。但是 Stackpanel 下的控件(仅在这种情况下为文本框)不应该是可编辑的,并且带有红色背景,因为附加属性在它们所属的 Stackpanel 中设置为 false。
发生什么了:
触发器在堆栈面板下的控件中不起作用,它们是可编辑的。
我认为正在发生的事情:
Style 再次为每个 Textbox 声明属性,这与它们从 Stackpanel 继承的属性不同。因此,根据样式,应启用控件。
我可以调整样式中的触发器,使其首先查找继承的属性,然后查找我根据我的视图模型的 IsEnabled 属性声明的默认值吗?是否有另一种我没有看到的方法来做到这一点?
编辑:澄清标题(我希望:D)
解决方案
因此,经过更多的研究和测试(非常感谢@Sinatr 为我指明了正确的方向),我找到了答案:
在附加属性上使用 MultiDatatrigger 并结合使用枚举而不是布尔值作为附加属性。
枚举:
public enum EnabledEnum
{
NotSet,
False,
True
}
附加属性类型更改为 typeof(EditableEnum) 并使用 NotSet 进行初始化:
static Properties()
{
EditableProperty = DependencyProperty.RegisterAttached("Editable", typeof(EditableEnum), typeof(EasyProperties), new FrameworkPropertyMetadata(EditableEnum.NotSet, FrameworkPropertyMetadataOptions.Inherits));
}
public static readonly DependencyProperty EditableProperty;
public static void SetEditable(DependencyObject dependencyObject, EditableEnum value)
{
dependencyObject.SetValue(EditableProperty, value);
}
public static EditableEnum GetEditable(DependencyObject dependencyObject)
{
return (EditableEnum)dependencyObject.GetValue(EditableProperty);
}
样式的新代码:
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsEnabled}" Value="False"/>
<Condition Binding="{Binding Path=(Properties:Properties.Editable),RelativeSource={RelativeSource Self}}" Value="NotSet"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrush}}"/>
<Setter Property="IsReadOnly" Value="True"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsEnabled}" Value="True"/>
<Condition Binding="{Binding Path=(Properties:Properties.Editable),RelativeSource={RelativeSource Self}}" Value="NotSet"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="IsReadOnly" Value="False"/>
</MultiDataTrigger>
<Trigger Property="EasyProperties:EasyProperties.Editable" Value="False">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrush}}"/>
<Setter Property="IsReadOnly" Value="True"/>
</Trigger>
<Trigger Property="Properties:Properties.Editable" Value="True">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="IsReadOnly" Value="False"/>
</Trigger>
</Style.Triggers>
这可以按预期与我的问题中的示例代码一起使用。唯一仍然困扰我的是 Style 中的重复。我尝试在 Multidatatrigger 中设置“Properties:Properties.Editable”,但这导致了 Stackoverflow。
推荐阅读
- azure - 如何在 Azure 存储的私有容器中下载文件夹
- php - 现代浏览器是否支持 onchange="this.form.submit()" 进行文件上传?
- java - 如何在没有注释的情况下序列化对象内的列表?
- azure - 带有容器的 Azure 应用服务不遵守使用 udp 进行端口转发的 docker-compose 语法
- python - 如何在python中使while循环更快?
- c# - EventHubProducerClient 是否提供带有单个 EventData 的 SendAsync?
- c++ - 如何在 c++ 中将指针与数组一起使用并返回指针值?
- sql - 我将如何根据偏好将结果限制为仅一个地址
- cmake - windows 10下qtcreator编译时出现权限错误
- ruby-on-rails - Stripe::AuthenticationError 未提供 API 密钥