迁移WPF至AvaloniaUI:如何从代码后台访问ViewModel?
问题:Avalonia迁移中代码后台设置DataContext无效,按钮点击UI无响应
我正在把旧WPF应用迁移到Avalonia UI(Reactive MVVM),之前WPF里用视图代码后台处理按钮点击的模式,能复用大量代码,但迁移到Avalonia后遇到问题:点击按钮修改ViewModel属性,UI完全没反应。
WPF原有工作模式
WPF视图(MainWindow.xaml)
<Window x:Class="WpfTest.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:WpfTest" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <TextBlock TextWrapping="Wrap" Text="{Binding Greeting}"/> <Button Content="Button" Click="Button_Click"/> </Grid> </Window>
WPF视图代码后台(MainWindow.xaml.cs)
namespace WpfTest { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { ViewModel myview = new ViewModel(); public MainWindow() { InitializeComponent(); this.DataContext = myview; } private void Button_Click(object sender, RoutedEventArgs e) { myview.Greeting = "Hello"; //…and here functions from other classes etc. are called } } }
WPF ViewModel(ViewModel.cs)
namespace WpfTest { internal class ViewModel:INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void RaisePropertyChange(string propertyname) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyname)); } } private string _greeting; public string Greeting { get { return _greeting; } set { _greeting = value; RaisePropertyChange("Greeting"); } } } }
Avalonia迁移后的代码
Avalonia ViewModel(MainWindowViewModel.cs)
namespace AvaloniaTest.ViewModels { public class MainWindowViewModel : ViewModelBase { private string? greeting; public string? Greeting { get => greeting; set => this.RaiseAndSetIfChanged(ref greeting, value); } } }
Avalonia视图代码后台(MainWindow.xaml.cs)
namespace AvaloniaTest.Views { public partial class MainWindow : Window { MainWindowViewModel myview = new MainWindowViewModel(); public MainWindow() { InitializeComponent(); this.DataContext = myview; } private void Button_Click(object sender, RoutedEventArgs e) { myview.Greeting = "Hello"; } } }
问题分析
确实是App.axaml.cs默认配置了ViewModel自动绑定,导致代码后台手动设置的DataContext被覆盖,代码里操作的myview并不是UI实际绑定的ViewModel实例,所以修改属性后UI无响应。
解决方法(沿用原有代码后台处理模式)
方法1:获取UI实际绑定的ViewModel实例
不要自行新建ViewModel,直接从控件的DataContext强转获取实际生效的实例:
namespace AvaloniaTest.Views { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); // 移除自行创建实例和设置DataContext的代码 } private void Button_Click(object sender, RoutedEventArgs e) { // 从DataContext获取真实绑定的ViewModel var viewModel = DataContext as MainWindowViewModel; if (viewModel != null) { viewModel.Greeting = "Hello"; // 此处可继续调用其他类的方法,和WPF模式完全一致 } } } }
方法2:取消App.axaml中自动绑定ViewModel的逻辑
如果希望继续自己控制DataContext,可以修改App.axaml,移除自动关联ViewModel的配置:
默认的App.axaml会包含类似如下的DataTemplate配置:
<Application xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:AvaloniaTest.ViewModels" x:Class="AvaloniaTest.App"> <Application.DataTemplates> <DataTemplate DataType="{x:Type vm:MainWindowViewModel}"> <views:MainWindow /> </DataTemplate> </Application.DataTemplates> <Application.Styles> <FluentTheme Mode="Light"/> </Application.Styles> </Application>
移除其中的DataTemplate节点后,就可以在代码后台手动设置DataContext,和WPF的原有模式保持一致。
内容的提问来源于stack exchange,提问作者Hatzegopteryx
相关产品推荐
相关产品推荐

