简体   繁体   中英

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.

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. And then, I want to put the mainPage on top of 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. 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. INotifyProperty says that the view model I implement for the current view changes as I press a button. 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.

I assumed that with INotifyPropertyChanged, the view will automatically change the UI value, but it does not. I already tried to set the mode for binding to Two Way , but it doesn't work. 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.

xaml of Main window is shown below

<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

<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

<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.

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. 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. Sorry for the inconvenience.

You defined a DataTemplate for MainPage (a UserControl) in App.xaml.

<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.

However, you added a code block shown below in 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. This seems to prevent the DataTemplate from working as expected.

So, the solution is to remove that code block in 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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