如何解决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何时更改,然后引发该事件。仅在通知框架任何数据绑定属性(在这种情况下为Convert
和WidgetMiddlePoint
)更改时才调用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>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。