簡體   English   中英

WPF 強制 xaml 重新獲取屬性的值,盡管屬性的 setter 沒有改變

[英]WPF force xaml to re-fetch the property's value although the property's setter didn't change

我正在修改一個現有的 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 何時更改,然后引發事件。 只有當框架收到任何數據綁定屬性(在本例中為WidgetMiddlePointActualWidth )更改的通知時,才會調用Convert方法。

您可以使用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,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>

Fody 有一個 PropertyChanged 插件

https://github.com/Fody/PropertyChanged它帶走了一些使用 INotifyPropertyChanged 的​​樣板文件

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM