c# - Canvas ActualWidth 和 ActualHeight 以 MVVM 方式传入 ViewModel
问题描述
最近我遇到了一个看似简单的问题:我想在我正在处理的一个应用程序中使用 Mode=OneWayToSource 将画布的 Width 和 Height 参数推送到 ViewModel 中。原来 Mode=OneWayToSource 对此不起作用,根据微软的说法,这是 WPF 的一个功能。好的。
无论如何,一段时间以来,我一直在思考如何在遵守 MVVM 原则的同时以最好的方式(即最短和最不混乱)做到这一点。我想出了以下几点:
/// <summary>
/// Sends graph dimensions to <see cref="GraphViewModel"/>
/// </summary>
public class SendGraphDimensionsToViewModelProperty : BaseAttachedProperty<SendGraphDimensionsToViewModelProperty, bool>
{
public override void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (!(sender is Canvas canvas))
return;
canvas.SizeChanged += (sender, e) =>
{
if (canvas.DataContext is GraphViewModel graph)
{
graph.Width = canvas.ActualWidth;
graph.Height = canvas.ActualHeight;
}
};
}
}
然后我只是将属性附加到带有 GraphViewModel 实例的 DataContext 的画布上:
local:SendGraphDimensionsToViewModelProperty.Value="True"
这按预期工作。基本上,附加属性的值在加载时从 null 更改为 true,这会触发 SizeChanged 事件,该事件监视 Canvas 的 ActualHeight 和 ActualWidth。
我的问题是:您是否建议对我的代码进行任何改进(例如与可能的内存泄漏等有关)?我只想在学习新东西的同时“MinMax”。我是一名初级开发人员,我不能真正向 IRL 咨询这个问题,因为我认识的人都没有 MVVM。我正在尝试以模块化方式编写所有内容,这意味着我想编写一次,然后在我再次需要时复制它以加快我开发应用程序的速度。
期待您的建议。
解决方案
我对这个问题的解决方案是一组附加属性,它们可以应用于任何 FrameworkElement 实例。
public static class perSizeBindingHelper
{
public static readonly DependencyProperty ActiveProperty = DependencyProperty.RegisterAttached(
"Active",
typeof(bool),
typeof(perSizeBindingHelper),
new FrameworkPropertyMetadata(OnActiveChanged));
public static bool GetActive(FrameworkElement frameworkElement)
{
return (bool) frameworkElement.GetValue(ActiveProperty);
}
public static void SetActive(FrameworkElement frameworkElement, bool active)
{
frameworkElement.SetValue(ActiveProperty, active);
}
public static readonly DependencyProperty BoundActualWidthProperty = DependencyProperty.RegisterAttached(
"BoundActualWidth",
typeof(double),
typeof(perSizeBindingHelper));
public static double GetBoundActualWidth(FrameworkElement frameworkElement)
{
return (double) frameworkElement.GetValue(BoundActualWidthProperty);
}
public static void SetBoundActualWidth(FrameworkElement frameworkElement, double width)
{
frameworkElement.SetValue(BoundActualWidthProperty, width);
}
public static readonly DependencyProperty BoundActualHeightProperty = DependencyProperty.RegisterAttached(
"BoundActualHeight",
typeof(double),
typeof(perSizeBindingHelper));
public static double GetBoundActualHeight(FrameworkElement frameworkElement)
{
return (double) frameworkElement.GetValue(BoundActualHeightProperty);
}
public static void SetBoundActualHeight(FrameworkElement frameworkElement, double height)
{
frameworkElement.SetValue(BoundActualHeightProperty, height);
}
private static void OnActiveChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
if (!(dependencyObject is FrameworkElement frameworkElement))
{
return;
}
if ((bool) e.NewValue)
{
frameworkElement.SizeChanged += OnFrameworkElementSizeChanged;
UpdateObservedSizesForFrameworkElement(frameworkElement);
}
else
{
frameworkElement.SizeChanged -= OnFrameworkElementSizeChanged;
}
}
private static void OnFrameworkElementSizeChanged(object sender, SizeChangedEventArgs e)
{
if (sender is FrameworkElement frameworkElement)
{
UpdateObservedSizesForFrameworkElement(frameworkElement);
}
}
private static void UpdateObservedSizesForFrameworkElement(FrameworkElement frameworkElement)
{
frameworkElement.SetCurrentValue(BoundActualWidthProperty, frameworkElement.ActualWidth);
frameworkElement.SetCurrentValue(BoundActualHeightProperty, frameworkElement.ActualHeight);
}
}
用法是...
<Grid ...
vhelp:perSizeBindingHelper.Active="True"
vhelp:perSizeBindingHelper.BoundActualHeight="{Binding GridHeight, Mode=OneWayToSource}"
vhelp:perSizeBindingHelper.BoundActualWidth="{Binding GridWidth, Mode=OneWayToSource}">
推荐阅读
- html - 悬停时将行添加到行
- php - SQL 员工总数
- python - 提交时的 Python 代码返回运行时错误 - NZEC
- r - R 'x' 中的问题必须是原子的”
- arraylist - 使用 Java 8 流将字符串列表分组到自定义对象中
- python - pandas.core.base.DataError:没有数字类型可以在只有数字的数据框中聚合
- gradle - 如何从 Gradle 启动和终止后台进程?
- dialogflow-es - Dialogflow Messenger 未在 UI 中显示丰富的消息,而完整的正常消息显示的是机器人而不是建议芯片
- javascript - 如何在 JavaScript 中定位具有不同类名的兄弟姐妹
- python - 从烧瓶中得到结果