简体   繁体   English

将控件的样式绑定到 Viewmodel 属性

[英]Binding the style of the control to a Viewmodel property

I am trying to create a banner with different states and colors to show messages to the user, showing a Border with a specific style and a Label with an style bases in the Border style and using DataTrigger .我正在尝试创建具有不同状态的横幅和 colors 以向用户显示消息,显示具有特定样式的Border和具有Border样式的样式基础的Label并使用DataTrigger I have created each custom styles for each state in my App.xaml and I am trying to change the state based on a property of my ViewModel. I have created each custom styles for each state in my App.xaml and I am trying to change the state based on a property of my ViewModel.

The problem is that the style doesn't change every time I change the property, but nevertheless if I modify some of the XAML during debugging, the style is refreshed correctly.问题是每次更改属性时样式都不会更改,但是如果我在调试期间修改 XAML 的某些部分,则样式会正确刷新。

Maybe I am missing a NotifyPropertyChanged somewhere?也许我在某处错过了NotifyPropertyChanged

Visual example:视觉示例:

在此处输入图像描述

This is My code:这是我的代码:

App.xaml with my defined styles and my custom converter App.xaml和我定义的 styles 和我的自定义转换器

<Application.Resources>

    <local:StyleConverter x:Key="StyleConverter" />

    <Style x:Key="Banner" TargetType="{x:Type Border}">
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="Padding" Value="10" />
        <Setter Property="CornerRadius" Value="5" />
    </Style>

    <Style x:Key="Banner_Info" TargetType="{x:Type Border}" BasedOn="{StaticResource Banner}">
        <Setter Property="Background" Value="#e3f7fc" />
        <Setter Property="BorderBrush" Value="#8ed9f6" />
    </Style>

    <Style x:Key="Banner_Error" TargetType="{x:Type Border}" BasedOn="{StaticResource Banner}">
        <Setter Property="Background" Value="#ffecec" />
        <Setter Property="BorderBrush" Value="#f5aca6" />
    </Style>

    <Style x:Key="Banner_Success" TargetType="{x:Type Border}" BasedOn="{StaticResource Banner}">
        <Setter Property="Background" Value="#e9ffd9" />
        <Setter Property="BorderBrush" Value="#a6ca8a" />
    </Style>

    <Style x:Key="Banner_Text" TargetType="{x:Type Label}">
        <Setter Property="FontWeight" Value="DemiBold"></Setter>
        <Style.Triggers>
            <DataTrigger Binding="{Binding BorderBrush.Color, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Border}}}" Value="#8ed9f6">
                <Setter Property="Foreground" Value="#31708F" />
            </DataTrigger>
            <DataTrigger Binding="{Binding BorderBrush.Color, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Border}}}" Value="#f5aca6">
                <Setter Property="Foreground" Value="#B10009" />
            </DataTrigger>
            <DataTrigger Binding="{Binding BorderBrush.Color, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Border}}}" Value="#a6ca8a">
                <Setter Property="Foreground" Value="#529214" />
            </DataTrigger>
        </Style.Triggers>
    </Style>

</Application.Resources>

Styleconverter.cs

public class StyleConverter : IValueConverter {
    public object Convert (object value, Type targetType, object parameter, CultureInfo culture) {
        if (targetType != typeof (Style)) {
            throw new InvalidOperationException ("The target must be a Style");
        }

        var styleProperty = parameter as string;
        if (value == null || styleProperty == null) {
            return null;
        }

        string styleValue = value.GetType ()
            .GetProperty (styleProperty)
            .GetValue (value, null)
            .ToString ();
        if (styleValue == null) {
            return null;
        }

        Style newStyle = (Style) Application.Current.TryFindResource (styleValue);
        return newStyle;
    }

    public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture) {
        throw new NotImplementedException ();
    }
}

Banner.cs

public class Banner : INotifyPropertyChanged {
    private string _Message;
    public string Message {
        get => _Message;
        private set {
            _Message = value;
            RaisePropertyChanged (null);
        }
    }

    private string _Style = "Banner_Success";
    public string Style {
        get => _Style;
        private set {
            _Style = value;
            RaisePropertyChanged (null);
        }
    }

    public Banner SetSuccess (string message) {
        Style = "Banner_Success";
        Message = message;

        return this;
    }

    public Banner SetInfo (string message) {
        Style = "Banner_Info";
        Message = message;

        return this;
    }

    public Banner SetError (string message) {
        Style = "Banner_Error";
        Message = message;

        return this;
    }

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged (string PropertyName) {
        PropertyChanged?.Invoke (this, new PropertyChangedEventArgs (PropertyName));
    }

    #endregion
}

Mainwindow.xml

<Grid>
    <StackPanel Orientation="Vertical" VerticalAlignment="Center">

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="2*"></ColumnDefinition>
                <ColumnDefinition Width="10*"></ColumnDefinition>
                <ColumnDefinition Width="2*"></ColumnDefinition>
            </Grid.ColumnDefinitions>

            <Border Grid.Column="1" Grid.Row="0" VerticalAlignment="Center" Style="{Binding ., Mode=TwoWay, Converter={StaticResource StyleConverter}, ConverterParameter=BannerStyle}">
                <Label Grid.Column="1" Style="{StaticResource Banner_Text}" Content="{Binding BannerMessage}" />
            </Border>
        </Grid>

        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <Button Padding="10" Margin="10" Content="BLUE" Command="{Binding CmdChangeColor, UpdateSourceTrigger=PropertyChanged}" CommandParameter="blue" />
            <Button Padding="10" Margin="10" Content="RED" Command="{Binding CmdChangeColor, UpdateSourceTrigger=PropertyChanged}" CommandParameter="red" />
            <Button Padding="10" Margin="10" Content="GREEN" Command="{Binding CmdChangeColor, UpdateSourceTrigger=PropertyChanged}" CommandParameter="green" />
        </StackPanel>

    </StackPanel>
</Grid>

MainViewModel.cs

public class MainViewModel : INotifyPropertyChanged {
    
    public Banner Banner { get; } = new Banner ();
    public string BannerStyle => Banner.Style;
    public string BannerMessage => Banner.Message;

    public RelayCommand CmdChangeColor { get; }

    public MainViewModel () {
        Banner.SetSuccess ("This is the initial message");

        CmdChangeColor = new RelayCommand (param => ChangeColor (param.ToString ()));
    }

    public void ChangeColor (string color) {
        switch (color) {
            case "blue":
                Banner.SetInfo ("INFO!! This should be a banner with blue background");
                break;

            case "red":
                Banner.SetError ("ERROR!! This should be a banner with red background");
                break;

            case "green":
                Banner.SetSuccess ("SUCCESS!! This should be a banner with green background");
                break;
        }

        RaisePropertyChanged (null);
    }

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged (string PropertyName) {
        PropertyChanged?.Invoke (this, new PropertyChangedEventArgs (PropertyName));
    }

    #endregion
}

bind to property which has notifications, instead of entire view model ( {Binding.} ).绑定到具有通知的属性,而不是整个视图 model ( {Binding.} )。 This way also simplifies converter (no more reflection)这种方式也简化了转换器(不再反射)

<Border Style="{Binding Path=Banner.Style, Converter={StaticResource StyleConverter}">
public class StyleConverter : IValueConverter {
    public object Convert (object value, Type targetType, object parameter, CultureInfo culture) {
        if (targetType != typeof (Style)) {
            throw new InvalidOperationException ("The target must be a Style");
        }

        string styleValue = value?.ToString();
        if (styleValue == null) {
            return null;
        }

        Style newStyle = (Style) Application.Current.TryFindResource (styleValue);
        return newStyle;
    }

    public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture) {
        throw new NotImplementedException ();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM