WPF - 以编程方式更改它的图像可视化效果错误

WPF - Wrong image visualization changing it programmatically

提问人:BugsFree 提问时间:11/17/2023 最后编辑:BugsFree 更新时间:11/17/2023 访问量:35

问:

我有两个窗口:

  • MainWindow 在 DataGrid 中加载图像并显示它们的预览
  • 双击 DataGrid 中显示相关图像的行时,将打开 ImageWindow

我想说的是,当 ImageWindow 打开时,用户按下左键或右键按钮,ImageWindow 将分别加载 DataGrid 中的上一个或下一个图像。

这是我到目前为止所做的:

ImageWindow.xaml

<Window x:Class="ImageBrowser.ImageWindow"
    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:ImageBrowser"
    xmlns:local1="clr-namespace:ImageBrowser.Controls"
    mc:Ignorable="d"
    Title="ImageWindow" KeyDown="Window_KeyDown" SourceInitialized="Window_SourceInitialized" WindowStartupLocation="CenterScreen">
<Grid x:Name="GridContainer" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid Grid.Row="0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="40"/>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition Width="40"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Button x:Name="ClosedCurveButton" Grid.Column="0" Background="LightBlue" ToolTip="Draw closed curve" Click="ClosedCurveButton_Click" HorizontalAlignment="Left">
            <Image Source="/Resources/spline.png"/>
        </Button>
        <Button x:Name="ClosedCurveInfoButton" Grid.Column="2" Background="LightBlue" ToolTip="Show curves info" Click="ClosedCurveInfoButton_Click"  HorizontalAlignment="Left">
            <Image Source="/Resources/statistic.png"/>
        </Button>
    </Grid>
    <Canvas Grid.Row="1" x:Name="canvasContainer" Height="{Binding ElementName=currentImg, Path=ActualHeight}" Width="{Binding ElementName=currentImg, Path=ActualWidth}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <Image x:Name="currentImg" Source="{Binding ImageBpm}"  Mouse.MouseEnter="CurrentImg_MouseEnter" Mouse.MouseLeave="CurrentImg_MouseLeave" 
           Mouse.MouseMove="CurrentImg_MouseMove" ContextMenuOpening="CurrentImg_ContextMenuOpening" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Loaded="Window_Loaded">
            <Image.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Set LandMark" Click="AddLandMark_Click" CommandParameter="{Binding MousePosition}"/>
                </ContextMenu>
            </Image.ContextMenu>
        </Image>
    </Canvas>
    <Label x:Name="CoordinatesLabel" Grid.Row="2" Visibility="Hidden" FontSize="14" HorizontalAlignment="Left">Image Ref x: {0} y:{1} - Grid Ref x: {2} y:{3}</Label>
</Grid>

图像窗口.cs

public partial class ImageWindow : Window, INotifyPropertyChanged
{

    private MainWindow _parent;

    public event EventHandler GoPrevius;

    public event EventHandler GoNext;

    private BitmapImage _imageBpm;

    public BitmapImage ImageBpm
    {
        get { return _imageBpm; }
        set
        {
            if (_imageBpm != value)
            {
                _imageBpm = value;
                OnPropertyChanged(nameof(ImageBpm));
            }
        }
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
    
    public ImageWindow(MainWindow parent, string imageName)
    {
        InitializeComponent();
        Title = imageName;
        _parent = parent;
        _parent.NewImage += _parent_NewImage;

        DataContext = this;
    }

    private void _parent_NewImage(object sender, NewImageEventArgs e)
    {
        RemoveLandMarks();
        ImageBpm = CreateImageSource(e.NewImageName);
        Title = e.NewImageName;
        ReloadLandMark(_parent.ImagesMap[Title]);
    }
    
    private BitmapImage CreateImageSource(string imageName = "")
    {
        string image = imageName.Equals("") ? Title : imageName;
        BitmapImage bitmapImage = new BitmapImage();
        try
        {
            using (MemoryStream memoryStream = new MemoryStream(_parent.ImagesMap[Title].ImageBytes))
            {
                bitmapImage.BeginInit();
                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                bitmapImage.StreamSource = memoryStream;
                memoryStream.Position = 0;
                bitmapImage.EndInit();
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show($"Error loading image: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
        }

        return bitmapImage;
    }

    private void Window_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Left)
        {
            GoPrevius?.Invoke(this, new EventArgs());
        }
        else if (e.Key == Key.Right)
        {
            GoNext?.Invoke(this, new EventArgs());
        }
    }
}

MainWindow.xaml.cs

public class NewImageEventArgs : EventArgs
{
    public string NewImageName { get; set; }

    public NewImageEventArgs(string newImageName)
    {
        NewImageName = newImageName;
    }
}

public partial class MainWindow : Window
{

    public Dictionary<string, LandMarkedImage> ImagesMap { get; } = new Dictionary<string, LandMarkedImage>();

    public event EventHandler<NewImageEventArgs> NewImage;
    
    private void ImageWindow_GoNext(object sender, EventArgs e)
    {
        if (ImageGrid.Items.Count - 1 > ImageGrid.SelectedIndex)
        {
            ImageGrid.SelectedIndex++;
            Item item = ImageGrid.SelectedItem as Item;
            NewImage?.Invoke(this, new NewImageEventArgs(item.Name));
        }
    }

    private void ImageWindow_GoPrevius(object sender, EventArgs e)
    {
        if (ImageGrid.SelectedIndex > 0)
        {
            ImageGrid.SelectedIndex--;
            Item item = ImageGrid.SelectedItem as Item;
            NewImage?.Invoke(this, new NewImageEventArgs(item.Name));
        }
    }
}

我得到的奇怪行为是,当我第一次按下向左或向右按钮时,图像没有改变。我确信事件被正确触发,因为我在调试中遵循了,并且因为 ImageWindow 的标题更改了新图像的名称,但图像本身没有遵循。

下面是一个例子:enter image description here

双击MainWindow中的凉亭图像:enter image description here

按下左键按钮:enter image description here

我读到这可能与BitmapImage的“激进”缓存有关,所以我尝试使用该标志,但随后软件开始崩溃,抛出缺少键的异常。我发现阅读这个答案我不能使用该标志,因为似乎只有当图像是从 URI 加载时才能使用它。BitmapCreateOptions.IgnoreImageCache

C# WPF

评论


答: 暂无答案