如何从 ViewModel 更改样式属性?
Posted
技术标签:
【中文标题】如何从 ViewModel 更改样式属性?【英文标题】:How to change the style property from the ViewModel? 【发布时间】:2021-02-09 06:10:17 【问题描述】:如何从 ViewModel 修改 Style 属性?我正在将 WPF 和 MVVM 与 Caliburn Micro 一起使用。我有两种不同的按钮样式,我想在用户单击按钮时从 ViewModel 更改它。
我正在尝试在我的 xaml 中使用它:
<Button
Style="Binding Path=StyleButton, Mode=OneWay"
Grid.Row="0"
Grid.Column="1"
Content="News"
x:Name="LoadFirstPage" />
【问题讨论】:
检查我更新的答案。希望对你有帮助 您不会更改视图模型的样式。如果你这样做,你首先不需要视图模型。尽管使用converter,但您可以根据某些视图模型属性的值在视图中设置Style
。
【参考方案1】:
将视图相关类型(如 Style
)放入视图模型中违反了 MVVM 原则。相反,公开一个表示按钮状态的属性,该状态决定是否应显示一种样式或另一种样式。
public class MyViewModel : INotifyPropertyChanged
private bool _isPageLoaded;
public bool IsPageLoaded
get => _isPageLoaded;
set
if (_isPageLoaded == value)
return;
_isPageLoaded = value;
OnPropertyChanged();
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
// ...other properties and methods.
一定要给它一个有意义的名字。它不必是bool
类型,但它适合这里。还要确保实现INotifyPropertyChanged
以反映用户界面中属性的更改。
将此属性设置为单击按钮时调用的命令或方法中的正确值。从这里开始,您的方案有多种选择。
样式触发解决方案
您可以使用触发器为两种状态创建一个通用样式,而不是完全交换样式,该触发器根据存储在属性中的状态以不同方式设置属性。
<Style x:Key="MyButtonStyle" TargetType="x:Type Button" BasedOn="StaticResource x:Type Button">
<!-- Properties set for IsPageLoaded=False -->
<Setter Property="Foreground" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="Binding IsPageLoaded" Value="True">
<!-- Properties set for IsPageLoaded=True -->
<Setter Property="Foreground" Value="Blue"/>
</DataTrigger>
</Style.Triggers>
</Style>
<Button Style="StaticResource MyButtonStyle"
Grid.Row="0"
Grid.Column="1"
Content="News"
x:Name="LoadFirstPage"/>
价值转换器解决方案
您可以创建一个返回与属性状态对应的样式的值转换器。
public class ConditionToStyleConverter : IValueConverter
public Style SuccessStyle get; set;
public Style FailureStyle get; set;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
return (bool)value ? SuccessStyle : FailureStyle;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
return new InvalidOperationException();
以下是您在范围内的资源字典中放入两种样式和一个转换器的示例。
<Style x:Key="MyFirstButtonStyle" TargetType="x:Type Button" BasedOn="StaticResource x:Type Button">
<Setter Property="Foreground" Value="Red"/>
</Style>
<Style x:Key="MySecondButtonStyle" TargetType="x:Type Button" BasedOn="StaticResource x:Type Button">
<Setter Property="Foreground" Value="Blue"/>
</Style>
<local:ConditionToStyleConverter x:Key="ConditionToStyleConverter"
SuccessStyle="StaticResource MyFirstButtonStyle"
FailureStyle="StaticResource MySecondButtonStyle"/>
您可以像这样在按钮上使用转换器。
<Button Style="Binding IsPageLoaded, Converter=StaticResource ConditionToStyleConverter"
Grid.Row="0"
Grid.Column="1"
Content="News"
x:Name="LoadFirstPage"/>
在此示例中,转换器是一个简单的IValueConverter
,它公开了样式的属性,因此对于不同的样式,您必须创建其他实例。也可以创建一个可以直接绑定样式的多值转换器,但是对于你作为初学者的场景,这个方案应该足够了。
【讨论】:
我不知道为什么,但是当我使用您的 Style Tigger 解决方案并更改 IsPageLoaded 属性时,我的项目中的内容控件不会加载内容。正是这段代码ActivateItem(new PostsViewModel());
这不起作用,但你的解决方案很棒,非常感谢。
@NicolasHL 该样式不应该引起任何这样的副作用,但很难说为什么它似乎会影响没有代码的ContentControl
。 ContentControl
是如何知道以前不存在的 IsPageLoaded
属性的?
这是在单击按钮时执行的代码部分。 public void LoadFirstPage() ActivateItem(new PostsViewModel()); IsPageLoaded = true;
我不知道代码是否正确,但这是您的解决方案对我的工作方式。
样式触发解决方案对我有用,谢谢以上是关于如何从 ViewModel 更改样式属性?的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI:如何从 ViewModel 的更改中切换警报演示者
Usercontrol - 从 ViewModel 通知属性更改
MVVM:修改模型,如何正确更新 ViewModel 和 View?