You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

请求将WPF C#代码后置转换为MVVM模式的完整实现指导

将代码后置的WPF示例转换为MVVM模式

需求说明

我的目标是把这个采用代码后置的简单WPF示例转换成MVVM模式,这能帮我理解之后怎么为自己的需求编写MVVM代码。我在学习MVVM时有盲区,希望能拿到完整可直接运行的文件,只说“把这段代码放进ViewModel”对我没用,因为构建完整的ViewModel正是我需要的。我花了很多时间看不符合当前需求的在线教程,所以来这里求助!这个示例里,用户选三个RadioButton中的一个,TextBlock和Label会显示对应的字符串。


原代码文件

MainWindow.xaml

<Window x:Class="VMTest.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:VMTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <StackPanel>
            <RadioButton x:Name="rbRed" Content="Red Means Stop" Checked="RbRed_Checked"/>
            <RadioButton x:Name="rbYellow" Content="Yellow Means Go Faster" Checked="RbYellow_Checked"/>
            <RadioButton x:Name="rbGreen" Content="Green Mean Go" Checked="RbGreen_Checked"/>
        </StackPanel>
        <TextBlock x:Name="myTextBlock" Grid.Row="1"/>
        <Label x:Name="myLabel" Grid.Row="2"/>
    </Grid>
</Window>

MainWindow.xaml.cs

using System.Windows;

namespace VMTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private readonly string LabelString1 = "1234567890";
        private readonly string LabelString2 = "ABCDEFGHIJ";
        private readonly string LabelString3 = "abcdefghij";

        public MainWindow()
        {
            InitializeComponent();
        }

        private void RbRed_Checked(object sender, RoutedEventArgs e)
        {
            myTextBlock.Text = rbRed.Content.ToString();
            myLabel.Content = LabelString1;
        }

        private void RbYellow_Checked(object sender, RoutedEventArgs e)
        {
            myTextBlock.Text = rbYellow.Content.ToString();
            myLabel.Content = LabelString2;
        }

        private void RbGreen_Checked(object sender, RoutedEventArgs e)
        {
            myTextBlock.Text = rbGreen.Content.ToString();
            myLabel.Content = LabelString3;
        }
    }
}

MVVM转换后的完整文件

1. ViewModel基类:ViewModelBase.cs

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Collections.Generic;

namespace VMTest
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected bool SetField<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(field, value)) return false;
            field = value;
            OnPropertyChanged(propertyName);
            return true;
        }
    }
}

2. 主ViewModel:MainViewModel.cs

namespace VMTest
{
    public class MainViewModel : ViewModelBase
    {
        private string _selectedRadioContent = string.Empty;
        private string _labelContent = string.Empty;

        private readonly Dictionary<string, string> _radioMapping = new()
        {
            {"Red Means Stop", "1234567890"},
            {"Yellow Means Go Faster", "ABCDEFGHIJ"},
            {"Green Mean Go", "abcdefghij"}
        };

        public string SelectedRadioContent
        {
            get => _selectedRadioContent;
            set
            {
                if (SetField(ref _selectedRadioContent, value))
                {
                    if (_radioMapping.TryGetValue(value, out var labelText))
                    {
                        LabelContent = labelText;
                    }
                }
            }
        }

        public string LabelContent
        {
            get => _labelContent;
            set => SetField(ref _labelContent, value);
        }
    }
}

3. 修改后的MainWindow.xaml

<Window x:Class="VMTest.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:VMTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <StackPanel>
            <RadioButton Content="Red Means Stop" 
                         IsChecked="{Binding SelectedRadioContent, Converter={StaticResource RadioButtonConverter}, ConverterParameter='Red Means Stop'}"/>
            <RadioButton Content="Yellow Means Go Faster" 
                         IsChecked="{Binding SelectedRadioContent, Converter={StaticResource RadioButtonConverter}, ConverterParameter='Yellow Means Go Faster'}"/>
            <RadioButton Content="Green Mean Go" 
                         IsChecked="{Binding SelectedRadioContent, Converter={StaticResource RadioButtonConverter}, ConverterParameter='Green Mean Go'}"/>
        </StackPanel>
        <TextBlock Text="{Binding SelectedRadioContent}" Grid.Row="1"/>
        <Label Content="{Binding LabelContent}" Grid.Row="2"/>
    </Grid>
    <Window.Resources>
        <local:RadioButtonToSelectionConverter x:Key="RadioButtonConverter"/>
    </Window.Resources>
</Window>

4. 绑定转换器:RadioButtonToSelectionConverter.cs

using System.Globalization;
using System.Windows.Data;

namespace VMTest
{
    public class RadioButtonToSelectionConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value?.ToString() == parameter?.ToString();
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? parameter : Binding.DoNothing;
        }
    }
}

5. 修改后的MainWindow.xaml.cs

using System.Windows;

namespace VMTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

关键说明

  • ViewModelBase:实现INotifyPropertyChanged接口,作为所有ViewModel的基类,负责属性变更通知,确保UI能实时响应数据变化。
  • MainViewModel:封装所有业务逻辑和数据,通过SelectedRadioContent属性接收RadioButton的选中状态,自动同步更新LabelContent。
  • RadioButton转换器:解决RadioButton与字符串属性的双向绑定问题,将IsChecked状态转换为对应的选中内容。
  • UI绑定:移除了原有的事件处理逻辑,所有UI元素通过数据绑定与ViewModel关联,实现UI视图与业务逻辑的完全分离。

内容的提问来源于stack exchange,提问作者ZioGio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 16:25:27