当前位置: 首页 > 知识库问答 >
问题:

MVVM中ItemsSource更改时未更新UI

百里海超
2023-03-14

所以我的应用程序有一个主窗口显示食谱列表,第二个窗口(从主窗口打开)添加新的食谱到列表(有信息)。两个窗口具有相同的视图模型。经过测试,新的制作方法被成功添加到列表中,但是UI没有更新新的制作方法。我也有一个删除按钮在主窗口为每个食谱和它的工作正常。删除的制作方法将在视图模型和UI中删除。我的代码相当长。我希望它是可读的。下面是我的代码(还有很多其他的UI,所以我只显示相关的代码):

主窗口视图

<!--Button to open second window-->
<Button Command="{Binding OpenAddRecipeWindowCommand}" Name="AddRecipeButton" Grid.Column="0" Margin="5" Padding="5" FontSize="15" Content="Add new recipe"/>

<!--The list-->
<ListView Name="RecipeList" Grid.Row="2" Margin="5" ItemsSource="{Binding RecipeModels}">
            <!-- Set the style for item container to stretch to full width-->
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                </Style>
            </ListView.ItemContainerStyle>

            <!-- Template of each item in the ListView -->
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition></ColumnDefinition>
                            <ColumnDefinition Width="Auto"></ColumnDefinition>
                        </Grid.ColumnDefinitions>

                        <TextBlock Name="RecipeName" Grid.Column="0" FontSize="15" Margin="5" VerticalAlignment="Center" Text="{Binding Name}"/>
                        <Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},
                                            Path=DataContext.DeleteRecipeCommand}"
                                CommandParameter="{Binding}"
                                Name="Delete" Grid.Column="1" FontSize="15" Margin="5" Padding="5" HorizontalAlignment="Right" Content="Delete"/>
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
            
        </ListView>

第二窗口视图

<DockPanel Margin="5">
        <!-- Recipe information -->
        <StackPanel DockPanel.Dock="Top">
            <!-- Name, amount, price input-->
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"></ColumnDefinition>
                    <ColumnDefinition Width="2*"></ColumnDefinition>
                    <ColumnDefinition Width="Auto"></ColumnDefinition>
                    <ColumnDefinition></ColumnDefinition>
                    <ColumnDefinition Width="Auto"></ColumnDefinition>
                    <ColumnDefinition></ColumnDefinition>
                </Grid.ColumnDefinitions>

                <TextBlock Grid.Column="0" Margin="5 5 0 5" Padding="5" FontSize="15" VerticalAlignment="Center" Text="Tên"/>
                <TextBox Grid.Column="1" Margin="0 5 5 5" Padding="2" VerticalAlignment="Center" Text="{Binding NewRecipe.Name}" FontSize="13"/>

                <TextBlock Grid.Column="2" Margin="5 5 0 5" Padding="5" FontSize="15" VerticalAlignment="Center" Text="Số lượng"/>
                <TextBox Grid.Column="3" Margin="0 5 5 5" Padding="2" VerticalAlignment="Center" Text="{Binding NewRecipe.Amount}" FontSize="13" MaxLength="9" PreviewTextInput="NumberValidationTextBox" />

                <TextBlock Grid.Column="4" Margin="5 5 0 5" Padding="5" FontSize="15" VerticalAlignment="Center" Text="Giá thành"/>
                <TextBox Grid.Column="5" Margin="0 5 5 5" Padding="2" VerticalAlignment="Center" Text="{Binding NewRecipe.Price}" FontSize="13" MaxLength="9" PreviewTextInput="NumberValidationTextBox" />
            </Grid>
            
            <!-- Checkbox and add ingredient button -->
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                </Grid.RowDefinitions>
                
                <CheckBox Grid.Row="0" Margin="10 5 10 5" VerticalContentAlignment="Center" VerticalAlignment="Center" FontSize="15" Content="Use as ingredient"/>
                <Button Grid.Row="1" Margin="10 5 10 5" Padding="5" FontSize="15" HorizontalAlignment="Left" Command="{Binding AddIngredientCommand}"  Content="Add new ingredient"/>
            </Grid>
        </StackPanel>

        <!-- ListView and buttons -->
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>

            <ListView Name="IngredientList" ItemsSource="{Binding Ingredients}" Grid.Row="0" Margin="5" >
                <ListView.ItemContainerStyle>
                    <Style TargetType="ListViewItem">
                        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                    </Style>
                </ListView.ItemContainerStyle>

                <!-- ListViewItem template -->
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"></ColumnDefinition>
                                <ColumnDefinition Width="2*"></ColumnDefinition>
                                <ColumnDefinition Width="Auto"></ColumnDefinition>
                                <ColumnDefinition></ColumnDefinition>
                                <ColumnDefinition Width="Auto"></ColumnDefinition>
                                <ColumnDefinition></ColumnDefinition>
                                <ColumnDefinition Width="Auto"></ColumnDefinition>
                                <ColumnDefinition></ColumnDefinition>
                                <ColumnDefinition Width="Auto"></ColumnDefinition>
                            </Grid.ColumnDefinitions>

                            <TextBlock Grid.Column="0" Margin="5 5 0 5" Padding="5" FontSize="13" Text="Name"/>
                            <TextBox Grid.Column="1" Margin="0 5 5 5" Padding="5" MaxLength="37" FontSize="13"/>

                            <TextBlock Grid.Column="2" Margin="5 5 0 5" Padding="5" FontSize="13" Text="Amount"/>
                            <TextBox Grid.Column="3" Margin="0 5 5 5" Padding="5" MaxLength="9" FontSize="13"/>

                            <TextBlock Grid.Column="4" Margin="5 5 0 5" Padding="5" FontSize="13" Text="Unit"/>
                            <TextBox Grid.Column="5" Margin="0 5 5 5" Padding="5" MaxLength="38" FontSize="13"/>

                            <TextBlock Grid.Column="6" Margin="5 5 0 5" Padding="5" FontSize="13" Text="Price"/>
                            <TextBox Grid.Column="7" Margin="0 5 5 5" Padding="5" MaxLength="9" FontSize="13"/>

                            <Button Grid.Column="8" Name="DeleteItemButton" Margin="5" Padding="5"
                                    Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},
                                            Path=DataContext.DeleteIngredientCommand}"
                                    CommandParameter="{Binding}"
                                    FontSize="13" Content="Delete"/>
                        </Grid>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            
            <!-- Buttons -->
            <DockPanel Grid.Row="1">
                <Button DockPanel.Dock="Right" Name="SaveButton" Margin="5" Padding="20 5 20 5" Command="{Binding SaveRecipeCommand}" FontSize="15" Content="Save"/>
                <Button DockPanel.Dock="Left" Name="CancelButton" Margin="5" Padding="20 5 20 5" HorizontalAlignment="Left" Command="{Binding CancelCommand}" FontSize="15" Content="Cancel"/>
            </DockPanel>
        </Grid>
    </DockPanel>

视图模型

    public class MainWindowViewModel : INotifyPropertyChanged
    {
        /// <summary>
        /// Implementation for Main window UI. 
        /// </summary>
        #region Main Window View Model
        // List of recipes which is the ItemsSource for ListViewItem
        #region ObservableCollection<RecipeModel> recipeModels

        private ObservableCollection<RecipeModel> recipeModels;

        public ObservableCollection<RecipeModel> RecipeModels
        {
            get
            {
                return recipeModels;
            }

            set
            {
                if (recipeModels != value)
                {
                    recipeModels = value;
                    RaisePropertyChanged(nameof(recipeModels));
                }
            }
        }
        #endregion

        #region Buttons
        // Add Recipe Window Button
        public RelayCommand OpenAddRecipeWindowCommand { get; set; }

        private void ExecuteOpenAddRecipeWindowCommand()
        {
            RecipeWindow newWindow = new RecipeWindow();
            newWindow.ShowDialog();
        }

        // Add Ingredient Window Button 
        public RelayCommand OpenAddIngredientWindowCommand { get; set; }

        private void ExecuteOpenAddIngredientWindowCommand()
        {
            RecipeWindow newWindow = new RecipeWindow();
            newWindow.ShowDialog();
        }

        // Product Calculation Window Button 
        public RelayCommand OpenProductCalculationWindowCommand { get; set; }

        private void ExecuteOpenProductCalculationWindowCommand()
        {
            RecipeWindow newWindow = new RecipeWindow();
            newWindow.ShowDialog();
        }

        // Product Calculation Window Button 
        public RelayCommand OpenIngredientCalculationWindowCommand { get; set; }

        private void ExecuteOpenIngredientCalculationWindowCommand()
        {
            RecipeWindow newWindow = new RecipeWindow();
            newWindow.ShowDialog();
        }

        // Delete Recipe Command
        public RelayCommand<object> DeleteRecipeCommand { get; set; }

        private void ExecuteDeleteRecipeCommand(object recipe)
        {
            RecipeModels.Remove((RecipeModel)recipe);
            Save();
        }

        #endregion

        #endregion

        /*------------------------------------------------------------------------------------------------------------------------------------*/
        /*------------------------------------------------------------------------------------------------------------------------------------*/
        /// <summary>
        /// Implementation for Recipe window UI
        /// </summary>
        #region Recipe Window View Model
        // List of ingredients which is ItemsSource for ListView
        #region ObservableCollection<RecipeModel> ingredients

        private ObservableCollection<IngredientModel> ingredients = new ObservableCollection<IngredientModel>();

        public ObservableCollection<IngredientModel> Ingredients
        {
            get
            {
                return ingredients;
            }

            set
            {
                if (ingredients != value)
                {
                    ingredients = value;
                    RaisePropertyChanged(nameof(ingredients));
                }
            }
        }
        #endregion

        // The recipe to be newly created, or edited.
        #region RecipeModel newRecipe
        private RecipeModel newRecipe = new RecipeModel();

        public RecipeModel NewRecipe
        {
            get
            {
                return newRecipe;
            }

            set
            {
                if (newRecipe != value)
                {
                    newRecipe = value;
                }
                RaisePropertyChanged(nameof(newRecipe));
            }
        }
        #endregion

        #region Buttons
        // Cancel command
        public RelayCommand CancelCommand { get; set; }

        public Action CloseWindow { get; set; }

        public void ExecuteCancelCommand()
        {
            CloseWindow();
        }

        // Add ingredient command
        public RelayCommand AddIngredientCommand { get; set; }

        public void ExecuteAddIngredientCommand()
        {
            Ingredients.Add(new IngredientModel());
        }

        // Delete ingredient command
        public RelayCommand<object> DeleteIngredientCommand { get; set; }

        public void ExecuteDeleteIngredientCommand(object ingredient)
        {
            Ingredients.Remove((IngredientModel)ingredient);
        }

/* THIS IS THE PART WHERE I TRY TO SAVE THE NEW RECIPE TO THE LIST BUT UI DOES NOT CHANGE */
        // Save command
        public RelayCommand SaveRecipeCommand { get; set; }

        public void ExecuteSaveRecipeCommand()
        {
            NewRecipe.ingredients = Ingredients;

            RecipeModels.Add(NewRecipe);

        /* I TESTED WITH A MESSAGE BOX TO SHOW THAT THE NEW RECIPE IS ADDED */
            string res = "";
            foreach (var item in RecipeModels)
            {
                res += item.Name + " ";
            }

            MessageBox.Show(res);
            CloseWindow();
        }

        #endregion

        #endregion

        /*------------------------------------------------------------------------------------------------------------------------------------*/
        /*------------------------------------------------------------------------------------------------------------------------------------*/
        /// <summary>
        /// Mutual Section
        /// </summary>
        #region Constructor
        public MainWindowViewModel(Action action)
        {
            // Load data from file
            Load();

            CloseWindow = action;

            #region Main Window buttons
            OpenAddRecipeWindowCommand = new RelayCommand(ExecuteOpenAddRecipeWindowCommand);

            OpenAddIngredientWindowCommand = new RelayCommand(ExecuteOpenAddIngredientWindowCommand);

            OpenProductCalculationWindowCommand = new RelayCommand(ExecuteOpenProductCalculationWindowCommand);

            OpenIngredientCalculationWindowCommand = new RelayCommand(ExecuteOpenIngredientCalculationWindowCommand);

            DeleteRecipeCommand = new RelayCommand<object>(ExecuteDeleteRecipeCommand);
            #endregion

            #region Add Ingredient Window buttons
            CancelCommand = new RelayCommand(ExecuteCancelCommand);

            SaveRecipeCommand = new RelayCommand(ExecuteSaveRecipeCommand);

            AddIngredientCommand = new RelayCommand(ExecuteAddIngredientCommand);

            DeleteIngredientCommand = new RelayCommand<object>(ExecuteDeleteIngredientCommand);
            #endregion
        }

        #endregion

        #region Property Change Notification
        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string property)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
        }

        #endregion

共有1个答案

卢树
2023-03-14

两个窗口具有相同的视图模型。

我怀疑他们有。我想他们有自己的同类实例。

您可以尝试在打开窗口时设置窗口的DataContext:

private void ExecuteOpenAddRecipeWindowCommand()
{
    RecipeWindow newWindow = new RecipeWindow();
    newWindow.DataContext = this;
    newWindow.ShowDialog();
}

则两个窗口应具有相同的DataContext

还要注意,直接在视图模型中创建窗口有效地破坏了MVVM设计模式

 类似资料:
  • 我想实现,让我们说温度单位转换器。我想使用AndroidMVVM和数据绑定来做到这一点,但我不知道如何。我有一个片段,它由三个编辑文本字段组成:摄氏度,华氏度,开尔文。更改其中之一后,其余部分应自动更新。在没有数据绑定的情况下,我将 TextWatcher 设置为每个字段,并在 onTextChanged 中执行所有验证和转换逻辑,并设置其他字段的值。在之前文本更改中,我删除了其他字段的侦听器,并

  • 我正在使用workbox-build-2.1。2和workbox-sw-2.1。2和Angular-cli-1.6。0,一切正常,但当我更新应用程序并为生产和软件构建它时。js文件被修改,然后在chrome浏览器中服务人员没有更新,它继续使用旧版本,直到我手动取消注册。如果不安装新软件。js文件,当它安装新版本时,它会自动清理网站上的旧数据并重新开始吗?还是我需要设置该部分?。 以下是我注册软件的

  • 我有一个表视图,每次都很好地填充, 我的主控制器: 我的测试类: 扩展测试类并覆盖其运行的Test1类: 我的aHandler: 因为tbl1绑定到Handler。getInstance()。GetData(),第一次初始化该类时,我看到列Test填充了值1,因为TestData=1;但当计时器开始更改测试数据时,表视图不会获得新的赋值。我做错了什么? 我尽我所能解释这个问题,请让我知道,如果它仍

  • 问题内容: 我试图弄清楚Angular的工作原理,并在模型更改时无法更新视图。 的HTML JS http://jsfiddle.net/N2G7z/ 有任何想法吗? 问题答案: 正如上面提到的Ajay beniwal一样,您需要使用Apply来开始消化。

  • 这个问题可能已经得到了回答,我读过很多类似的,但对我不起作用。因此,我的具有扩展的自定义表模型。我的数据是和列名。那么,当我的数据发生更改时,如何更新表呢?我一直在使用,它正在工作,但它将我的自定义单元格呈现器重置为默认值。谢了。

  • 问题内容: 我有两个定义如下的实体bean(删除了无关的东西): CriticalItems定义如下: 在我的DAO代码中-我有以下方法: 当我加载MasterItem时,它会正确加载,并且还会按照指示加载CriticalItems Set中的数据。然后,我将此数据发送到我的UI,并获得更新的副本,然后尝试将其保留。用户更新MasterItem对象中的字段,但不触摸CriticalItems Se