在MVVM架构中,ViewModel通常不应该直接访问视图层(如窗口)的属性,因为这违反了关注点分离的原则。ViewModel应该专注于业务逻辑和数据处理,而视图相关的操作应该由View来处理。
最推荐的方式是通过数据绑定将窗口属性暴露给ViewModel:
// 在窗口类中
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
// 将窗口宽度绑定到ViewModel
var binding = new Binding("WindowWidth")
{
Source = DataContext,
Mode = BindingMode.TwoWay
};
this.SetBinding(WidthProperty, binding);
}
}
// ViewModel
public class MainViewModel : INotifyPropertyChanged
{
private double _windowWidth;
public double WindowWidth
{
get => _windowWidth;
set
{
_windowWidth = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public static class WindowProperties
{
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.RegisterAttached(
"ViewModel",
typeof(object),
typeof(WindowProperties),
new PropertyMetadata(null, OnViewModelChanged));
public static void SetViewModel(Window element, object value)
{
element.SetValue(ViewModelProperty, value);
}
public static object GetViewModel(Window element)
{
return element.GetValue(ViewModelProperty);
}
private static void OnViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Window window && e.NewValue is INotifyPropertyChanged vm)
{
vm.PropertyChanged += (sender, args) =>
{
if (args.PropertyName == "WindowWidth")
{
window.Width = (double)vm.GetType().GetProperty("WindowWidth").GetValue(vm);
}
};
}
}
}
// 定义事件
public class WindowSizeChangedEvent
{
public double Width { get; set; }
public double Height { get; set; }
}
// 在窗口代码中发布事件
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
EventAggregator.Instance.Publish(new WindowSizeChangedEvent
{
Width = e.NewSize.Width,
Height = e.NewSize.Height
});
}
// 在ViewModel中订阅事件
public class MainViewModel
{
public MainViewModel()
{
EventAggregator.Instance.Subscribe<WindowSizeChangedEvent>(e =>
{
WindowWidth = e.Width;
WindowHeight = e.Height;
});
}
public double WindowWidth { get; set; }
public double WindowHeight { get; set; }
}
推荐使用数据绑定或事件聚合器模式,它们保持了MVVM的分离原则,同时实现了需求。直接访问窗口属性应作为最后手段,仅在绝对必要时使用。
没有搜到相关的文章