wpf 为什么我通过应用程序添加的图像没有出现在它的控件中,而其他图像却出现了?

rlcwz9us  于 2023-10-22  发布在  其他
关注(0)|答案(1)|浏览(164)

这个项目是一个WPF应用程序,旨在帮助用户学习日本汉字字符。该应用程序有多个页面,包括一个主页面,用户可以与汉字字符进行交互并查看其相关的详细信息。该应用程序的主要功能之一是能够添加新的汉字字符及其相关信息,如平假名,发音,翻译和笔画数。当添加新元素时,它应该显示在主页上,但这里有一个问题。
该项目的基本图像的构建操作设置为“内容”,但如果我不把它设置为“内容”,图像将不会显示(请参阅文章末尾的图像)。但是,在编译阶段之后,新映像将在应用程序运行时动态添加到应用程序中。这些动态添加的图像不能正确显示在主页上,尽管与汉字字符相关的所有信息都能正确显示。有趣的是,调试器没有报告任何错误,这使得解决问题更加复杂。
下面是我的代码:
-----KanjiPageViewModel.cs-----

using Japonais.Model;
using Japonais.Utilities;
using Japonais.View;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace Japonais.ViewModel
{
    class KanjiPageViewModel : ViewModelBase
    {
        /* -------------------- Variable -------------------- */
        private Stack<string> Next_Stack = new();
        private Stack<string> Previous_Stack = new();
        private int cpt;
        private int TotalKanji;
        private Dictionary<string, KanjiData> imageToKanjiData = new();
        private string imageName = string.Empty;

        /* -------------------- Command -------------------- */
        public RelayCommand HomePageCommand => new(execute => HomePageAction());
        public RelayCommand AddKanjiCommand => new(execute => AddKanjiAction());
        public RelayCommand PreviousCommand => new(execute => PreviousAction());
        public RelayCommand NextCommand => new(execute => NextAction());
        public RelayCommand UpdateNumberOfKanjiCommand => new(execute => UpdateNumberOfKanji());

        /* -------------------- Properties -------------------- */
        // Kanji
        private bool _isKanjiChecked;
        public bool IsKanjiChecked
        {
            get { return _isKanjiChecked; }
            set
            {
                _isKanjiChecked = value;
                OnPropertyChanged();
            }
        }

        // Hiragana
        private bool _isHiraganaChecked;

        public bool IsHiraganaChecked
        {
            get { return _isHiraganaChecked; }
            set
            {
                _isHiraganaChecked = value;
                OnPropertyChanged();
            }
        }

        // Pronunciation
        private bool _isPronunciationChecked;

        public bool IsPronunciationChecked
        {
            get { return _isPronunciationChecked; }
            set
            {
                _isPronunciationChecked = value;
                OnPropertyChanged();
            }
        }

        // Translation
        private bool _isTranslationChecked = true;

        public bool IsTranslationChecked
        {
            get { return _isTranslationChecked; }
            set
            {
                _isTranslationChecked = value;
                OnPropertyChanged();
            }
        }

        // Number Of Strokes
        private bool _isNbOfStrokesChecked;

        public bool IsNbOfStrokesChecked
        {
            get { return _isNbOfStrokesChecked; }
            set
            {
                _isNbOfStrokesChecked = value;
                OnPropertyChanged();
            }
        }

        // All Check/Uncheck
        private bool _toggleAllChecked;

        public bool ToggleAllChecked
        {
            get { return _toggleAllChecked; }
            set
            {
                _toggleAllChecked = value;
                IsKanjiChecked = !IsKanjiChecked;
                IsHiraganaChecked = !IsHiraganaChecked;
                IsPronunciationChecked = !IsPronunciationChecked;
                IsTranslationChecked = !IsTranslationChecked;
                IsNbOfStrokesChecked = !IsNbOfStrokesChecked;
                OnPropertyChanged();
            }
        }

        // Current Image
        private ImageSource _currentImage = new BitmapImage(new Uri("/Images/Graphismes/No Image.png", UriKind.Relative));

        public ImageSource CurrentImage
        {
            get { return _currentImage; }
            set
            {
                _currentImage = value;
                OnPropertyChanged();
            }
        }

        // TextBlock Hiragana
        private string _hiraganaText = string.Empty;

        public string HiraganaText
        {
            get { return _hiraganaText; }
            set
            {
                _hiraganaText = value;
                OnPropertyChanged();
            }
        }

        // TextBlock Pronunciation
        private string _pronunciationText = string.Empty;

        public string PronunciationText
        {
            get { return _pronunciationText; }
            set
            {
                _pronunciationText = value;
                OnPropertyChanged();
            }
        }

        // TextBlock Translation
        private string _translationText = string.Empty;

        public string TranslationText
        {
            get { return _translationText; }
            set
            {
                _translationText = value;
                OnPropertyChanged();
            }
        }

        // TextBlock NumberOfStrokes
        private string _nbOfStrokesText = string.Empty;

        public string NbOfStrokesText
        {
            get { return _nbOfStrokesText; }
            set
            {
                _nbOfStrokesText = value;
                OnPropertyChanged();
            }
        }

        // Number of kanji done
        private string _kanjiText = string.Empty;

        public string KanjiText
        {
            get { return _kanjiText; }
            set
            {
                _kanjiText = value;
                OnPropertyChanged();
            }
        }

        /* -------------------- Method -------------------- */
        private void HomePageAction()
        {
            FrameManager.MainFrame?.Navigate(new Uri("/View/HomePage.xaml", UriKind.Relative));
        }

        public void AddKanjiAction()
        {
            FrameManager.MainFrame?.Navigate(new Uri("/View/AddKanjiPage.xaml", UriKind.Relative));
        }

        private void PreviousAction()
        {
            if (Previous_Stack.Count > 1)
            {
                cpt--;
                string previousImage = Previous_Stack.Pop();
                Next_Stack.Push(imageName);
                LoadImage(previousImage);
                imageName = previousImage;

                if (imageToKanjiData.TryGetValue(previousImage, out var data))
                {
                    HiraganaText = data.Hiragana;
                    PronunciationText = data.Pronunciation;
                    TranslationText = data.Translation;
                    NbOfStrokesText = data.NumberOfStrokes.ToString();
                }

                UpdateNumberOfKanjiCommand.Execute(null);
            }
            else
            {
                MessageBox.Show("You can't go back anymore. If you want to continue, click the button 'Next'.");
            }
        }

        private void NextAction()
        {
            if (Next_Stack.Count > 0)
            {
                cpt++;
                string nextImage = Next_Stack.Pop();
                Previous_Stack.Push(imageName);
                LoadImage(nextImage);
                imageName = nextImage;

                if (imageToKanjiData.TryGetValue(nextImage, out var data))
                {
                    HiraganaText = data.Hiragana;
                    PronunciationText = data.Pronunciation;
                    TranslationText = data.Translation;
                    NbOfStrokesText = data.NumberOfStrokes.ToString();
                }

                UpdateNumberOfKanjiCommand.Execute(null);
            }
            else
            {
                MessageBoxResult result = MessageBox.Show("You have reached the end. Do you want to restart ?","Restart ?", MessageBoxButton.YesNo);

                if (result == MessageBoxResult.Yes)
                {
                    Next_Stack.Clear();
                    Previous_Stack.Clear();

                    InitializeNextStack();
                }
            }
        }

        public void InitializeNextStack()
        {
            List<string> randomImageList = Images.GetRandomImageList(@"./Images/Kanji/");

            foreach (string image in randomImageList)
            {
                KanjiData kanjiData = JsonData.LoadKanjiDataFromJson(image);
                imageToKanjiData[image] = kanjiData;

                Next_Stack.Push(image);
            }
            string nextImage = Next_Stack.Pop();
            Previous_Stack.Push(nextImage);
            LoadImage(nextImage);
            imageName = nextImage;

            if (imageToKanjiData.TryGetValue(nextImage, out var data))
            {
                HiraganaText = data.Hiragana;
                PronunciationText = data.Pronunciation;
                TranslationText = data.Translation;
                NbOfStrokesText = data.NumberOfStrokes.ToString();
            }

            cpt = 1;
            TotalKanji = Next_Stack.Count;
            UpdateNumberOfKanjiCommand.Execute(null);
        }

        public void UpdateNumberOfKanji()
        {
            KanjiText = $"{cpt}/{TotalKanji+1}";
        }

        private void LoadImage(string imageRelativePath)
        {
            CurrentImage = new BitmapImage(new Uri($"/Images/Kanji/{imageRelativePath}", UriKind.Relative));
        }
    }
}

-----AddKanjiPageViewModel.cs-----

using Japonais.Model;
using Japonais.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows;
using System.Drawing;
using Microsoft.Win32;
using System.IO;

namespace Japonais.ViewModel
{
    class AddKanjiPageViewModel : ViewModelBase
    {
        /* -------------------- Variable -------------------- */
        private string selectedFilePath = string.Empty;

        /* -------------------- Command -------------------- */
        public RelayCommand GoBackCommand => new(execute => GoBackAction());
        public RelayCommand SelectImageCommand => new(execute => SelectImageAction());
        public RelayCommand SaveCommand => new(execute => SaveAction());

        /* -------------------- Properties -------------------- */
        // Current Image
        private ImageSource _currentImage = new BitmapImage(new Uri("/Images/Graphismes/No Image.png", UriKind.Relative));

        public ImageSource CurrentImage
        {
            get { return _currentImage; }
            set
            {
                _currentImage = value;
                OnPropertyChanged();
            }
        }

        // TextBox Hiragana
        private string _hiraganaTextBox = string.Empty;

        public string HiraganaTextBox
        {
            get { return _hiraganaTextBox; }
            set
            {
                _hiraganaTextBox = value;
                OnPropertyChanged();
            }
        }

        // TextBox Pronunciation
        private string _pronunciationTextBox = string.Empty;

        public string PronunciationTextBox
        {
            get { return _pronunciationTextBox; }
            set
            {
                _pronunciationTextBox = value;
                OnPropertyChanged();
            }
        }

        // TextBox Translation
        private string _translationTextBox = string.Empty;

        public string TranslationTextBox
        {
            get { return _translationTextBox; }
            set
            {
                _translationTextBox = value;
                OnPropertyChanged();
            }
        }

        // TextBox NbOfStrokes
        private string _nbOfStrokesTextBox = string.Empty;

        public string NbOfStrokesTextBox
        {
            get { return _nbOfStrokesTextBox; }
            set
            {
                _nbOfStrokesTextBox = value;
                OnPropertyChanged();
            }
        }

        /* -------------------- Method -------------------- */
        private void GoBackAction()
        {
            FrameManager.MainFrame?.Navigate(new Uri("/View/KanjiPage.xaml", UriKind.Relative));
        }

        private void SelectImageAction()
        {
            OpenFileDialog openFileDialog = new()
            {
                Filter = "Images (*.jpg, *.jpeg, *.png, *.gif, *.bmp)|*.jpg;*.jpeg;*.png;*.gif;*.bmp|All Files (*.*)|*.*",
                FilterIndex = 0,
                Multiselect = false
            };

            bool? result = openFileDialog.ShowDialog();

            if (result == true)
            {
                selectedFilePath = openFileDialog.FileName;
                CurrentImage = new BitmapImage(new Uri(selectedFilePath));
            }
        }

        private void SaveAction()
        {
            if (IsFormValid())
            {
                KanjiData kanjiData = new()
                {
                    ImageName = Path.GetFileName(selectedFilePath),
                    Hiragana = HiraganaTextBox,
                    Pronunciation = PronunciationTextBox,
                    Translation = TranslationTextBox,
                    NumberOfStrokes = int.Parse(NbOfStrokesTextBox)
                };

                Images.CopyImageToKanjiFolder(selectedFilePath);
                JsonData.AddKanjiToKanjiJson(kanjiData);

                CurrentImage = new BitmapImage(new Uri("/Images/Graphismes/No Image.png", UriKind.Relative));
                selectedFilePath = string.Empty;

                HiraganaTextBox = string.Empty;
                PronunciationTextBox = string.Empty;
                TranslationTextBox = string.Empty;
                NbOfStrokesTextBox = string.Empty;
            }
            else
            {
                MessageBox.Show("Please complete all fields, and select an image.");
            }
        }

        private bool IsFormValid()
        {
            if (string.IsNullOrEmpty(HiraganaTextBox) || string.IsNullOrEmpty(PronunciationTextBox) ||
                string.IsNullOrEmpty(TranslationTextBox) || string.IsNullOrEmpty(NbOfStrokesTextBox))
            {
                return false;
            }

            if (string.IsNullOrEmpty(selectedFilePath))
            {
                return false;
            }

            return true;
        }
    }
}

-----Images.cs-----

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Resources;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace Japonais.Model
{
    class Images
    {
        /* -------------------- Method -------------------- */
        public static List<string> GetRandomImageList(string relativePath)
        {
            var imageExtensions = new[] { ".jpg", ".jpeg", ".png", ".gif" };
            List<string> randomImageList = Directory.GetFiles(relativePath)
                                                    .Where(file => imageExtensions.Contains(Path.GetExtension(file).ToLower()))
                                                    .Select(file => Path.GetFileName(file))
                                                    .ToList();

            Random random = new();
            int n = randomImageList.Count;
            while (n > 1)
            {
                n--;
                int k = random.Next(n + 1);
                (randomImageList[n], randomImageList[k]) = (randomImageList[k], randomImageList[n]);
            }
            return randomImageList;
        }

        public static void CopyImageToKanjiFolder(string sourcePath)
        {
            try
            {
                if (File.Exists(sourcePath))
                {
                    string destinationFolder = @"./Images/Kanji/";
                    string fileName = Path.GetFileName(sourcePath);
                    string destinationPath = Path.Combine(destinationFolder, fileName);

                    File.Copy(sourcePath, destinationPath, true);
                }
                else
                {
                    MessageBox.Show("The source file does not exist.");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("An error occurred while copying the image : \n" + ex.Message);
            }
        }
    }
}

我使用调试器检查了图像的路径,图像是否添加到相应的文件夹中,以及信息是否添加到json文件中。从我所看到的,一切都是正常的(或者说应该是正常的)。
我试着将构建操作从“内容”改为“资源”,甚至是“嵌入式资源”,但我无法解决我的问题(当时我不知道这是不可能的)。

问题:

  • 如何使添加的图像(当我的程序运行时)在测试期间可见?
  • 如果我在编译之前没有将所有图像的Build Action设置为“Content”,则图像将不会显示。如何使他们显示,即使没有“内容”(也许它会解决我的问题时,图像是动态添加)?

When the Kanji is correctly shown
When the Kanji added manually is not shown

ryhaxcpt

ryhaxcpt1#

在这个问题上花了几个星期(分散在2个月以上),我终于找到了解决方案!所以对于任何感兴趣的人来说,以下是解决我问题的方法:

首先,为了找出问题所在,我必须寻找我对调试器不了解(而且还不够了解)的地方。我在我的“LoadImage”方法上放置了一个断点,以检查未显示的图像的路径。通过将鼠标移到它上面,您可以向下滚动列表以获取更多信息。而这份资料,竟然有错误!(见下图)
Error for the image not showing
为了查看确切的错误消息,我在方法中添加了这个,因为“Height”有一个错误。
-----AddKanjiPageViewModel.cs-----

private void LoadImage(string imageRelativePath)
{
    try
    {
        CurrentImage = new BitmapImage(new Uri(absoluteImagePath, UriKind.Absolute));

        double Height = CurrentImage.Height;
    }
    catch (IOException ex)
    {
        MessageBox.Show("Error loading image: " + ex.Message);
    }
}

这样,错误就会出现。这个问题来自于在编译前添加的图像和动态添加的图像之间的路径变化。

这个问题的解决方法如下:

-----AddKanjiPageViewModel.cs-----

private void LoadImage(string imageRelativePath)
{
    string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
    string relativeImagePath = $"Images/Kanji/{imageRelativePath}";
    string absoluteImagePath = Path.Combine(baseDirectory, relativeImagePath);

    try
    {
        CurrentImage = new BitmapImage(new Uri(absoluteImagePath, UriKind.Absolute));
    }
    catch (IOException ex)
    {
        MessageBox.Show("Error loading image: " + ex.Message);
    }
}

由于这一点,我们得到了程序启动位置的绝对路径(AppDomain.CurrentDomain.BaseDirectory; ),并且我们将图像所在的位置与程序启动的位置相结合(Path .Combine(baseDirectory,relativeImagePath); )。我们传入URI absoluteImagePath
多亏了这一点,我有图像显示没有任何担心!(见下图)
Everything now works!(显示的图像是一个十字,这只是为了使它非常显眼,以免错过它)

相关问题