简体   繁体   English

更改数据后视图的值不更新

[英]Values of View don't update after changing data

I'm trying to build an application that collects information of dams and weather forecasts from api and shows the data to users.我正在尝试构建一个应用程序,从 api 收集水坝和天气预报信息并将数据显示给用户。

As shown below, the main page is supposed to look similar for dam information and weather forcast information.如下所示,主页应该与大坝信息和天气预报信息相似。 Blue print蓝图

So, I want to make a component for card, that I can reuse for the data.所以,我想为卡片制作一个组件,我可以将它重用于数据。 In other words, I want to put 1) mainCards into 2)mainPage, so that I can have a page full of cards.换句话说,我想把 1) mainCards 放到 2)mainPage 中,这样我就可以拥有一个充满卡片的页面。 And then, I want to put the mainPage on top of 3)mainWindow.然后,我想将 mainPage 放在 3)mainWindow 之上。

I want to change the values inside of the purple cards when I click a menu button on the left side that says "Dam Info" and "Weather Info".当我单击左侧显示“大坝信息”和“天气信息”的菜单按钮时,我想更改紫色卡片内的值。 When I press the "Dam Info" button, I want the purple cards to fetch dam data from an API and show it on the screen.当我按下“大坝信息”按钮时,我希望紫色卡片从 API 获取大坝数据并将其显示在屏幕上。 Same for "Weather Info" button.与“天气信息”按钮相同。

The problem is, I can clearly see that the values that I binded to the text blocks in the cards change when I run the code and show them on console.问题是,当我运行代码并在控制台上显示它们时,我可以清楚地看到绑定到卡片中文本块的值发生了变化。 But, the actual UI doesn't update the change.但是,实际的 UI 不会更新更改。 INotifyProperty says that the view model I implement for the current view changes as I press a button. INotifyProperty 表示当我按下按钮时,我为当前视图实现的视图模型会发生变化。 It also says that the values(that I binded to the textblocks for purple cards) in a view model for purple card components change when I press a button.它还说,当我按下按钮时,紫色卡片组件的视图模型中的值(我绑定到紫色卡片的文本块)会发生变化。

I implemented a base class that implemented INotifyPropertyChanged for all view models, and RelayCommand for all commands.我实现了一个基类,它为所有视图模型实现了 INotifyPropertyChanged,并为所有命令实现了 RelayCommand。

I assumed that with INotifyPropertyChanged, the view will automatically change the UI value, but it does not.我假设使用 INotifyPropertyChanged,视图会自动更改 UI 值,但事实并非如此。 I already tried to set the mode for binding to Two Way , but it doesn't work.我已经尝试将绑定模式设置为 Two Way ,但它不起作用。 I tried to set certain values in a view model for Main Page(page that contains a lot of purple card components) and then make the purple card view model to fetch and reflect it.我尝试在主页(包含大量紫色卡片组件的页面)的视图模型中设置某些值,然后使紫色卡片视图模型获取并反映它。 But it doesn't work.但它不起作用。

Please help me.请帮我。 I've been dealing with this problem for a week.我已经处理这个问题一个星期了。 I have not much time left to just struggle with changing views and their components.我没有太多时间来努力改变视图及其组成部分。 I'm new to MVVM pattern and WPF and completely lost.我是 MVVM 模式和 WPF 的新手,完全迷路了。

xaml of Main window is shown below主窗口的 xml 如下所示

<Grid>
    <RadioButton Content="Dam Info"
            Command="{Binding ChangeMainPageForDamCommand}"
            CommandParameter="Dam"/>
    <RadioButton Content="Weather Info"
            Command="{Binding ChangeMainPageForWeatherCommand}"
            CommandParameter="Weather"/>
    <RadioButton Content="My data"
            Command="{Binding DetailPageCommand}"/>

    <ContentControl Content="{Binding CurrentView,
            Mode=TwoWay,
            UpdateSourceTrigger=PropertyChanged}"/>
</Grid>

view model for main window is shown below主窗口的视图模型如下所示

private object _currentView;
    public object CurrentView
    {
        get { return _currentView; }
        set
        {
            _currentView = value;
            OnPropertyChanged();
        }
    }


    public RelayCommand MainPageCommand { get; set; }
    public RelayCommand DetailPageCommand { get; set; }

    public RelayCommand ChangeMainPageForDamCommand { get; set; }

    public RelayCommand ChangeMainPageForWeatherCommand { get; set; }


    public MainPageViewModel DamMainPageVM { get; set; }


    public MainPageViewModel WeatherMainPageVM { get; set; }


    public MainPageViewModel MainPageVM { get; set; }
    public DetailPageViewModel DetailPageVM { get; set; }


    public MainWindowViewModel()
    {
        MainPageVM = new MainPageViewModel("Dam");

        CurrentView = MainPageVM;

        DetailPageVM = new DetailPageViewModel();

        ChangeMainPageForDamCommand = new RelayCommand(o =>
        {
            CurrentView = null;
            DamMainPageVM = new MainPageViewModel("Dam");
            CurrentView = DamMainPageVM;
            Debug.WriteLine("ChangeMainPageFor  Dam  Command executed");
        });

        ChangeMainPageForWeatherCommand = new RelayCommand(o =>
        {
            WeatherMainPageVM = new MainPageViewModel("Weather");
            CurrentView = WeatherMainPageVM;
            Debug.WriteLine("ChangeMainPageFor  Weather  Command executed");
        });

        DetailPageCommand = new RelayCommand(o =>
        {
            CurrentView = DetailPageVM;
        });
    }

xaml for mainPage that contains cards is shown below包含卡片的 mainPage 的 xml 如下所示

<Grid>
    <components:MainCard/>
    <components:MainCard/>
    <components:MainCard/>
    <components:MainCard/>
    <components:MainCard/>
    <components:MainCard/>
</Grid>

view model for the main page is shown below主页的视图模型如下所示

public MainCardDatum MainCardDatumItem = new MainCardDatum();

    public RelayCommand GetDamDetailCommand { get; set; }

    private MainCardViewModel _mainCardViewModel;
    public MainCardViewModel MainCardViewModel
    {
        get
        {
            return _mainCardViewModel;
        }
        set
        {
            _mainCardViewModel = value;
            OnPropertyChanged(nameof(MainCardViewModel));
        }
    }

    public MainPageViewModel() { }
    public MainPageViewModel(string pageName)
    {
        var d = new MainCardViewModel(pageName);
        GetMainPage(pageName);
        Debug.WriteLine(pageName+" is ON");
    }
    
    public void GetMainPage(string pageName)
    {
        GenerateMainCard(pageName);

        Debug.WriteLine(pageName+" made the page.");
    }
    
    private void GenerateMainCard(string pageName)
    {
        if (pageName == "Dam")
        {
            MainCardDatumItem.Id = 1;
            MainCardDatumItem.MainCardName = "damDummyInfoName";
            MainCardDatumItem.MainCardOption = "damDummyInfoOption";
        }
        else if (pageName == "Weather")
        {
            MainCardDatumItem.Id = 1;
            MainCardDatumItem.MainCardName = "weatherDummyInfoName";
            MainCardDatumItem.MainCardOption = "weatherDummyInfoOption";
        }
        else
        {
            Debug.Write("What?");
        }
    }

Main Card(Purple card component) xaml is below主卡(紫卡组件)xaml 如下

<Grid>
    <StackPanel>
        <TextBlock Name="nameHehe" 
               Text="{Binding MainCardName,
                        Mode=TwoWay,
                        UpdateSourceTrigger=PropertyChanged}"/>

        <TextBlock Name="optionHehe"
                Text="{Binding MainCardOption}"/>
    </StackPanel>

    <Button Background="Transparent"
            Command="{Binding GetDamDetailCommand}"/>
</Grid>

Finally, the view model for the main card(purple card component) is below最后,主卡(紫色卡组件)的视图模型如下

public MainPageViewModel MainPageVM = new MainPageViewModel();

    private string _mainCardName;
    public string MainCardName
    {
        get
        {
            return _mainCardName;
        }
        set
        {
            _mainCardName = value;
            OnPropertyChanged(nameof(MainCardName));
        }
    }

    private string _mainCardOption;
    public string MainCardOption
    {
        get
        {
            return _mainCardOption;
        }
        set
        {
            _mainCardOption = value;
            OnPropertyChanged(nameof(MainCardOption));
        }
    }

    public RelayCommand ClickCommand { get; set; }
    public RelayCommand GetDamDetailCommand { get; set; }
    public RelayCommand GetWeatherDetailCommand { get; set; }

    public MainCardViewModel()
    {
        GenerateCardsForDam();

        GetDamDetailCommand = new RelayCommand(o =>
        {
            MainCardName = "changed1";
            MainCardOption = "changed2";
        });
    }
    public MainCardViewModel(string pageName)
    {
        if (pageName == "Dam")
            GenerateCardsForDam();
        else
            GenerateCardsForWeather();

        GetDamDetailCommand = new RelayCommand(o =>
        {
            GenerateCardsForWeather();
        });
    }

    public void GenerateCardsForDam()
    {
        MainCardName = "DamName1";
        MainCardOption = "DamOption1";
        Debug.WriteLine("GenerateCardsForDam executed");
    }
    public void GenerateCardsForWeather()
    {
        MainCardName = "WeatherName1";
        MainCardOption = "WeatherOption1";
        Debug.WriteLine("GenerateCardsForWeather executed");
    }

I deleted out all unnecessary codes that are not related to this problem in xaml.我在 xaml 中删除了所有与此问题无关的不必要代码。

What am I doing wrong?我究竟做错了什么? Please help.请帮忙。

Also, it would be wonderful to know any discord server that I can ask and answer questions related to programming.另外,很高兴知道我可以提出和回答与编程相关的问题的任何不和谐服务器。 I'm having a hard time to explain this problem in text tbh.我很难在文本中解释这个问题。 Please let me know if you know one.如果你知道,请告诉我。

Thank you so much for reading so far.非常感谢您到目前为止的阅读。 Sorry for messy explanation.抱歉解释混乱。

https://github.com/yk170901/dnw.git Above is my Github repository for the project. https://github.com/yk170901/dnw.git上面是我的项目的Github存储库。 I tried to add it correctly, but somehow the project folder become empty when I try to upload it.我尝试正确添加它,但是当我尝试上传它时,项目文件夹以某种方式变为空。 So I added a zip, I hope you can see the problem with the zip file.所以我添加了一个 zip,希望你能看到 zip 文件的问题。 Sorry for the inconvenience.带来不便敬请谅解。

You defined a DataTemplate for MainPage (a UserControl) in App.xaml.您在 App.xaml 中为 MainPage(一个用户控件)定义了一个 DataTemplate。

<DataTemplate DataType="{x:Type viewModel:MainPageViewModel}">
    <view:MainPage/>
</DataTemplate>

When this DataTemplate is applied, it is expected to instantiate a MainPage and set the instance of MainPageViewModel to MainPage's DataContext.应用此 DataTemplate 时,应实例化 MainPage 并将 MainPageViewModel 的实例设置为 MainPage 的 DataContext。

However, you added a code block shown below in MainPage.xaml.但是,您在 MainPage.xaml 中添加了如下所示的代码块。

<UserControl.DataContext>
    <viewModels:MainPageViewModel/>
</UserControl.DataContext>

This means that when a MainPage is instantiated, an instance of MainPageViewModel will be instantiated as well and that instance will be set to MainPage's DataContext.这意味着当 MainPage 被实例化时,MainPageViewModel 的一个实例也将被实例化,并且该实例将被设置为 MainPage 的 DataContext。 This seems to prevent the DataTemplate from working as expected.这似乎阻止了 DataTemplate 按预期工作。

So, the solution is to remove that code block in MainPage.xaml.因此,解决方案是在 MainPage.xaml 中删除该代码块。

In addition, I found that the appearace of MainPage will be the same regardless of the instance of MainPageViewModel and so you will not be able to check the difference from its appearance.此外,我发现无论 MainPageViewModel 实例如何,MainPage 的外观都是相同的,因此您将无法从外观上检查差异。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM