微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用转换器应用并绑定到其他对象的属性的样式在运行时不会被覆盖 问题:XAML:虚拟机:转换器:样式:注意事项:我尝试过的:

如何解决使用转换器应用并绑定到其他对象的属性的样式在运行时不会被覆盖 问题:XAML:虚拟机:转换器:样式:注意事项:我尝试过的:

问题:

第一次加载窗口时设置样式,然后我无法替换它。

XAML:

Style="{Binding Path=BoolProperty,Converter={StaticResource ButtonStyleConverter}}"

虚拟机:

属性

public bool BoolProperty => SomeOtherObject.YetAnotherObject.OtherBoolProperty;

在构造函数中:

SomeOtherObject.YetAnotherObject.PropertyChanged += (s,a)
                    => PropertyChanged.Notify(this,nameof(BoolProperty));

转换器:

样式:

  • 经证明,样式是正确的,不会导致这种情况下的问题(请参阅解决方

注意事项:

  • Notify() 只是为了方便使用 IPropertyChanged 的​​扩展方法
  • 在根事件和所有通知、转换器调用等之后调用相同的 Notify() 时,样式会正确更新

我验证了以下内容

  • 当引起改变的事件发生时,PropertyChanged.Notify 被正确调用
  • 然后按预期调用 BoolProperty 的 getter
  • 调用转换器之后,我确认它返回了正确的样式
  • 在 Live Property Explorer 中检查样式时,很明显第一个样式仍然设置

我尝试过的:

  • .Notify(this,nameof(BoolProperty)) 更改为 .NotifyAll(this)
  • 先应用​​第二种样式(看看是不是样式本身的问题)
  • 添加UpdateSourceTrigger=PropertyChanged}
  • 仅用 Path=BoolProperty 替换 BoolProperty
  • 使用属性名称添加 ConverterParameter 属性

解决方案/变通方法

感谢@EldHasp,我能够验证它实际上不是 XAMl/Converter/Style 问题,而是与 Notify() 调用的方式有关。 我不知道为什么在所有调用/线程完成后 UI 没有更新,但我通过替换来修复它:

SomeOtherObject.YetAnotherObject.PropertyChanged += (s,nameof(BoolProperty));

与:

this.Command_That_Also_Relies_On_OtherBoolProperty.CanExecuteChanged += (s,a) 
    => PropertyChanged.Notify(this,nameof(BoolProperty));

虽然是 hack,但在我的情况下,这种解决方法是可以接受的,因为我没有时间进一步调查根本原因。 为了完成,命令如下所示:

public ICommand SomeCommand_That_Also_Relies_On_YetAnotherObject => new RelayCommand(
            () =>  /* some code */,() => SomeOtherObject.YetAnotherObject.OtherBoolProperty);

该命令还需要以下内容才能刷新:

CommandManager.InvalidateRequerySuggested();

看起来问题是 Notify() 不是从主线程调用的。

实际解决方案:

Raising OnPropertyChanged when an object property is modified from another thread

解决方法

问题显然不在您展示的代码中。 这是最简单的例子,效果很好。

using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace StyleBindingConverter
{
    public class BooleanToStyleConverter : IValueConverter
    {
        public Style TrueStyle { get; set; }
        public Style FalseStyle { get; set; }

        private static readonly BooleanConverter boolConverter = new BooleanConverter();
        public object Convert(object value,Type targetType,object parameter,CultureInfo culture)
        {
            if (!(value is bool boolean))
            {
                string str = value?.ToString();
                if (string.IsNullOrWhiteSpace(str) ||
                    !boolConverter.IsValid(str))
                    return DependencyProperty.UnsetValue;

                boolean = (bool)boolConverter.ConvertFromString(value.ToString());
            }


            return boolean
                ? TrueStyle
                : FalseStyle;

        }

        public object ConvertBack(object value,CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
namespace StyleBindingConverter
{
    public class BooleanViewModel
    {
        public bool BoolProperty { get; set; }
    }
}
<Window x:Class="StyleBindingConverter.TestStyleConverterWindow"
        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:StyleBindingConverter"
        mc:Ignorable="d"
        Title="TestStyleConverterWindow" Height="450" Width="400">
    <Window.Resources>
        <Style x:Key="Button.Style.True" TargetType="Button">
            <Setter Property="Background" Value="Green"/>
        </Style>
        <Style x:Key="Button.Style.False" TargetType="Button">
            <Setter Property="Background" Value="LightCoral"/>
        </Style>
        <local:BooleanToStyleConverter x:Key="BooleanToStyleConverter"
                                       FalseStyle="{StaticResource Button.Style.False}"
                                       TrueStyle="{StaticResource Button.Style.True}"/>
    </Window.Resources>
    <Window.DataContext>
        <local:BooleanViewModel/>
    </Window.DataContext>
    <UniformGrid Columns="1">
        <Button Content="Test Button" HorizontalAlignment="Center" VerticalAlignment="Center"
                Padding="15 5"
                Style="{Binding BoolProperty,Converter={StaticResource BooleanToStyleConverter},Mode=OneWay}"/>
        <CheckBox Content="Style Change" HorizontalAlignment="Center" VerticalAlignment="Center"
                IsChecked="{Binding BoolProperty,Mode=TwoWay}"/>
    </UniformGrid>
</Window>

异步对属性、通知和转换器的行为绝对没有影响。

这是异步更改属性的示例。 使用了主题中 INotifyPropertyChanged 的基本实现:BaseInpc

using Simplified;
using System.Timers;

namespace StyleBindingConverter
{
    public class BooleanViewModelAsync : BaseInpc
    {
        private bool _boolProperty;

        public bool BoolProperty { get => _boolProperty; private set => Set(ref _boolProperty,value); }

        private readonly Timer timer = new Timer() { Interval = 1000};

        public BooleanViewModelAsync()
        {
            timer.Elapsed += (s,e) => BoolProperty = !BoolProperty;
            timer.Start();
        }
    }

}
<Window x:Class="StyleBindingConverter.TestStyleConverterAsyncWindow"
        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:StyleBindingConverter"
        mc:Ignorable="d"
        Title="TestStyleConverterAsyncWindow"
        Height="450" Width="400">
    <Window.Resources>
        <Style x:Key="Button.Style.True" TargetType="Button">
            <Setter Property="Background" Value="Green"/>
        </Style>
        <Style x:Key="Button.Style.False" TargetType="Button">
            <Setter Property="Background" Value="LightCoral"/>
        </Style>
        <local:BooleanToStyleConverter x:Key="BooleanToStyleConverter"
                                       FalseStyle="{StaticResource Button.Style.False}"
                                       TrueStyle="{StaticResource Button.Style.True}"/>
    </Window.Resources>
    <Window.DataContext>
        <local:BooleanViewModelAsync/>
    </Window.DataContext>
    <Grid>
        <Button Content="Test Button" HorizontalAlignment="Center" VerticalAlignment="Center"
                Padding="15 5"
                Style="{Binding BoolProperty,Mode=OneWay}"/>
    </Grid>
</Window>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?