[英]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 何時更改,然后引發事件。 只有當框架收到任何數據綁定屬性(在本例中為WidgetMiddlePoint
和ActualWidth
)更改的通知時,才會調用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.