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

WPF .NET 6.0中更新Image Source不显示问题求助

问题描述

我正在开发一款应用,需实现显示代码生成图片的功能。我能生成图片并创建新Source,但在ViewModel中替换后图片无法显示。为复现问题编写了最小化测试程序,请问我遗漏了什么?我之前有个使用代码后台的类似应用,通过Dispatcher的Invoke方法替换新BitmapImage作为图片Source是有效的。

ViewModel代码

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Threading;

namespace TestImgs.ViewModels;

public class MainViewModel : ObservableObject
{
    public BitmapImage RedImg { get; set; } = null;
    public BitmapImage BlueImg { get; set; } = null;
    public BitmapImage GreenImg { get; set; } = null;
    public ICommand RenderCmd { get; set; }

    private readonly Dispatcher dispatcher;

    public MainViewModel()
    {
        dispatcher = Application.Current.Dispatcher;
        RenderCmd = new RelayCommand(Render);
    }

    public void Render()
    {
        dispatcher.Invoke(() => RedImg = GetSolidImg(Color.Red));
        dispatcher.Invoke(() => BlueImg = GetSolidImg(Color.Blue));
        dispatcher.Invoke(() => GreenImg = GetSolidImg(Color.Green));
    }

    private static BitmapImage GetSolidImg(Color color)
    {
        var bmp = new Bitmap(1024, 1024);
        using var gfx = Graphics.FromImage(bmp);
        using var brush = new SolidBrush(color);
        gfx.FillRectangle(brush, 0, 0, 1024, 1024);
        using var stream = new MemoryStream();
        bmp.Save(stream, ImageFormat.Bmp);
        stream.Position = 0;
        var img = new BitmapImage();
        img.BeginInit();
        img.StreamSource = stream;
        img.CacheOption = BitmapCacheOption.OnLoad;
        img.EndInit();
        img.Freeze();
        return img;
    }
}

视图代码

<Page
    x:Class="TestImgs.Views.MainPage"
    Style="{DynamicResource MahApps.Styles.Page}"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:properties="clr-namespace:TestImgs.Properties"
    xmlns:vms="clr-namespace:TestImgs.ViewModels" d:DataContext="{d:DesignInstance Type=vms:MainViewModel}"
    mc:Ignorable="d"
    d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="48" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Button Grid.Row="0" Content="Render squares" Command="{Binding Path=RenderCmd}" />
        <Grid
            Grid.Row="1"
            Background="{DynamicResource MahApps.Brushes.Gray10}">
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>

            <Image Grid.Column="0" Stretch="Fill" Source="{Binding Path=RedImg, Mode=OneWay}" />
            <Image Grid.Column="1" Stretch="Fill" Source="{Binding Path=BlueImg, Mode=OneWay}" />
            <Image Grid.Column="2" Stretch="Fill" Source="{Binding Path=GreenImg, Mode=OneWay}" />
        </Grid>
    </Grid>
</Page>

我的代码与网上类似解决方案一致,但仍无法正常显示。


问题修复方案

核心问题是未触发属性变更通知。虽然继承了ObservableObject,但直接使用自动属性赋值时,不会向WPF绑定系统发送属性值变化的信号,导致UI无法感知更新。

具体修复步骤

  1. 使用CommunityToolkit.Mvvm提供的[ObservableProperty]特性,让框架自动生成带变更通知的属性;
  2. 合并Dispatcher调用,减少UI线程调度开销。

修改后的ViewModel代码

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Threading;

namespace TestImgs.ViewModels;

public partial class MainViewModel : ObservableObject
{
    [ObservableProperty]
    private BitmapImage redImg;

    [ObservableProperty]
    private BitmapImage blueImg;

    [ObservableProperty]
    private BitmapImage greenImg;

    public ICommand RenderCmd { get; set; }

    private readonly Dispatcher dispatcher;

    public MainViewModel()
    {
        dispatcher = Application.Current.Dispatcher;
        RenderCmd = new RelayCommand(Render);
    }

    public void Render()
    {
        dispatcher.Invoke(() =>
        {
            RedImg = GetSolidImg(Color.Red);
            BlueImg = GetSolidImg(Color.Blue);
            GreenImg = GetSolidImg(Color.Green);
        });
    }

    private static BitmapImage GetSolidImg(Color color)
    {
        var bmp = new Bitmap(1024, 1024);
        using var gfx = Graphics.FromImage(bmp);
        using var brush = new SolidBrush(color);
        gfx.FillRectangle(brush, 0, 0, 1024, 1024);
        using var stream = new MemoryStream();
        bmp.Save(stream, ImageFormat.Bmp);
        stream.Position = 0;
        var img = new BitmapImage();
        img.BeginInit();
        img.StreamSource = stream;
        img.CacheOption = BitmapCacheOption.OnLoad;
        img.EndInit();
        img.Freeze();
        return img;
    }
}

说明

  • [ObservableProperty]特性会自动生成包含SetProperty逻辑的公开属性,当属性值变化时自动触发PropertyChanged事件,WPF绑定系统会立即更新UI;
  • 把多个赋值操作放到同一个dispatcher.Invoke调用中,避免多次线程切换,提升执行效率。

内容的提问来源于stack exchange,提问作者Miguel Pérez García

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:25:25