WPF强制xaml重新获取属性的值,尽管属性的设置器未更改

问题描述

我正在工作中修改一个现有的WPF项目(WPF我对WPF经验不足),并且我具有以下属性

public Point WidgetMiddlePoint
    {
        get
        {
            return new PointByAppMonitorDPI(_middlePoint);
            //return _middlePoint;
        }
    }

用户界面方面:

<controls1:BorderWithTip.TipOffset>
    <MultiBinding Converter="{StaticResource TipOffsetPositionConverter}">
        <Binding Path="WidgetMiddlePoint" Delay="500"  NotifyOnSourceUpdated="False" NotifyOnTargetUpdated="False"/>
        <Binding ElementName="BorderWithTip" Path="ActualWidth" Delay="500" NotifyOnSourceUpdated="False" NotifyOnTargetUpdated="False"/>
    </MultiBinding>
</controls1:BorderWithTip.TipOffset>

TipOffsetPositionConverter根据给定的参数执行一些计算。
我的问题是WidgetMiddlePoint值取决于应用程序所驻留的监视器的DPI(DPI与我的问题无关,这只是一个用例,仅当调用getter时才将其考虑在内)。
因此,发生的事情是UI会从getter中获取值,并且不会刷新该值,除非我使用setter将其设置为其他值,然后“通知”。

我如何配置UI使其每次都重新获取值,即使它“认为”该属性的值没有更改?还是不好的做法,不推荐?

解决方法

如果您希望框架调用您的getter并因此调用您的转换器,则应实现INotifyPropertyChanged并在视图模型中引发PropertyChanged事件。

您需要以某种方式确定DPI何时更改,然后引发该事件。仅在通知框架任何数据绑定属性(在这种情况下为ConvertWidgetMiddlePoint)更改时才调用ActualWidth方法。

,

Fody有一个PropertyChanged加载项

https://github.com/Fody/PropertyChanged 使用INotifyPropertyChanged会花费一些样板

,

您可以使用一个Window DpiChanged事件以及INotifyPropertyChanged。

下面的代码显示了如何执行此操作。它具有RecalculateMiddlePoint方法,该方法创建一个测试点,该测试点同时具有X和Y值的当前DPI,但显然应该进行适当的计算。

如果创建WPF应用程序,则下面的代码将中间点绑定到标签,并因此在屏幕之间拖动时在主窗口上显示变化的DPI。该代码可在.NET Framework 4.8和.NET Core 3.1中使用。

C#

public partial class MainWindow : Window,INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        // Hook the DpiChanged event
        this.DpiChanged += Window_DpiChanged;
        // Initialize our bound property
        WidgetMiddlePoint = RecalculateMiddlePoint(VisualTreeHelper.GetDpi(this));
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void Window_DpiChanged(object sender,DpiChangedEventArgs e)
    {
        Debug.WriteLine($"Old Scale: {e.OldDpi.DpiScaleX} New Scale: {e.NewDpi.DpiScaleX} " + 
                        $"Old PPI: {e.OldDpi.PixelsPerInchX} New PPI: {e.NewDpi.PixelsPerInchX}");
        // Recalculate _widgetMiddlePoint based on the values above and just set it
        WidgetMiddlePoint = RecalculateMiddlePoint(e.NewDpi);
    }

    private Point RecalculateMiddlePoint(DpiScale newDpi)
    {
        // Recalculate based on the new DPI in here
        // For testing we just create a 'Point' that has the PPI for X and Y values
        return new Point(newDpi.PixelsPerInchX,newDpi.PixelsPerInchX);
        //return new PointByAppMonitorDPI(_middlePoint);  // Correct code????
    }

    private Point _middlePoint;
    public Point WidgetMiddlePoint
    {
        get { return _middlePoint; }
        set
        {
            _middlePoint = value;
            PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(nameof(WidgetMiddlePoint)));
        }
    }
}

XAML

<Window x:Class="WpfApp9.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:WpfApp9"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Label Content="{Binding Path=WidgetMiddlePoint}" HorizontalAlignment="Left" Margin="0,0" VerticalAlignment="Top" Width="120"/>
    </Grid>
</Window>

添加到app.manifest:

  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings"> PerMonitor</dpiAwareness>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
  </application>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...