如何强制更新视图

Posted

技术标签:

【中文标题】如何强制更新视图【英文标题】:How to force update a view 【发布时间】:2014-03-17 06:45:58 【问题描述】:

我有一个包含两个Views 和一个ViewModel 的应用程序。 第一个View[AddView] 用于创建对象,second[ShowView] 用于显示对象。 ViewModel[DummyData]ObservableCollection 和创建新对象所需的一切组成。

我的问题是: 当我从AddView 添加对象时如何强制更新ShowView

这是虚拟数据

#region Fake Database
    private static ObservableCollection<Student> fakeStudentDataLayer;

    public UserDummyData()
    
        fakeStudentDataLayer = new ObservableCollection<Student>()
        
            new Student()Name = "test1", Surname = "surnameTest1", Age = 22, Barcode = "testbarcode1", ClassLetter = 'A', ClassNumber = 6, ID = 1, ParentName = "parentTest1", ParentSurname = "ParentSurnameTitle1", Number = 22, DateOfCreation = new DateTime(2008, 12, 2), LastCheckIn = new DateTime(2014, 3, 9),
            new Student()Name = "test2", Surname = "surnameTest2", Age = 22, Barcode = "testbarcode2", ClassLetter = 'B', ClassNumber = 8, ID = 2, ParentName = "parentTest2", ParentSurname = "ParentSurnameTitle2", Number = 22, DateOfCreation = new DateTime(2008, 12, 2), LastCheckIn = new DateTime(2014, 3, 9),
            new Student()Name = "test3", Surname = "surnameTest3", Age = 22, Barcode = "testbarcode3", ClassLetter = 'C', ClassNumber = 10, ID = 3, ParentName = "parentTest3", ParentSurname = "ParentSurnameTitle3", Number = 22, DateOfCreation = new DateTime(2008, 12, 2), LastCheckIn = new DateTime(2014, 3, 9) 
        ;
    

    public ObservableCollection<Student> FakeStudentDataLayer
    
        get  return fakeStudentDataLayer; 
        set  fakeStudentDataLayer = value; RaisePropertyChanged("FakeStudentDataLayer"); 
    
    #endregion

    #region Commands
    private RelayCommand _addStudentCommand;
    public ICommand NewStudentCommand
    
        get
        
            return _addStudentCommand
                ?? (_addStudentCommand = new RelayCommand(() =>
                
                    //Create new student
                    Student student = new Student();

                    //Set new student's properties
                    //TODO: Add ID value
                    student.Name = Name;
                    student.Surname = Surname;
                    student.ParentName = ParentName;
                    student.ParentSurname = ParentSurname;
                    student.ClassLetter = Convert.ToChar(ClassLetter.ToUpper());
                    student.ClassNumber = NumberConvertor(ClassNumber);
                    student.Class = Appender(ClassLetter, ClassNumber);
                    student.Number = Int32.Parse(Number);
                    student.Age = AgeConvertor(Age);
                    student.Barcode = Barcode;
                    student.ID = 6;
                    student.LastCheckIn = DateTime.Now;
                    student.DateOfCreation = DateTime.Now;

                    //TODO: ADD student to DATABASE
                    FakeStudentDataLayer.Add(student);
                ));
        
    
    #endregion

这里是 AddView

<Grid>
    <!--DataContext-->
    <Grid.DataContext>
        <dc:UserDummyData/>
    </Grid.DataContext>

    <!--Student TextBoxes-->
    <TextBlock x:Name="StudentNameWaterMark"
               Grid.Column="2"
               Text="x:Static p:Resources.Name"
               Style="StaticResource WaterMarkStyle"
               Visibility="Binding
                    ElementName=StudentNameContentTextBox, 
                    Path=Text.IsEmpty, Converter=StaticResource 
                    WaterMarkRemover"/>
    <TextBox x:Name="StudentNameContentTextBox"
             Grid.Column="2"
             Text="Binding Name"
             Width="Binding ElementName=StudentNameWaterMark,
                Path=Width"
             Style="StaticResource BasicTextBoxTextStyle"
             Background="Transparent">
    </TextBox>
    <TextBlock Name="StudentSurnameWaterMark"
               Grid.Column="2" Grid.Row="1"
               Text="x:Static p:Resources.Surname"
               Style="StaticResource WaterMarkStyle"
               Visibility="Binding
                    ElementName=StudentSurnameContentTextBox,
                    Path=Text.IsEmpty, Converter=StaticResource 
                    WaterMarkRemover"/>
    <TextBox x:Name="StudentSurnameContentTextBox"
             Grid.Column="2" Grid.Row="1"
             Text="Binding Surname"
             Width="Binding ElementName=StudentSurnameWaterMark,
                Path=Width"
             Style="StaticResource BasicTextBoxTextStyle"
             Background="Transparent">
    </TextBox>

    <!--Parent TextBoxes-->
    <TextBlock x:Name="ParentNameWaterMark"
               Grid.Column="2" Grid.Row="2"
               Text="x:Static p:Resources.ParentName"
               Style="StaticResource WaterMarkStyle"
               Visibility="Binding 
                    ElementName=ParentNameContentTextBox, 
                    Path=Text.IsEmpty, Converter=StaticResource 
                    WaterMarkRemover"/>
    <TextBox x:Name="ParentNameContentTextBox"
             Grid.Column="2" Grid.Row="2"
             Text="Binding ParentName"
             Width="Binding ElementName=ParentNameWaterMark,
                Path=Width"
             Style="StaticResource BasicTextBoxTextStyle"
             Background="Transparent">
    </TextBox>
    <TextBlock x:Name="ParentSurnameWaterMark"
               Grid.Column="2" Grid.Row="3"
               Text="x:Static p:Resources.ParentSurname"
               Style="StaticResource WaterMarkStyle"
               Visibility="Binding 
                      ElementName=ParentSurnameContentTextBox, 
                      Path=Text.IsEmpty, Converter=StaticResource 
                      WaterMarkRemover"/>
    <TextBox x:Name="ParentSurnameContentTextBox"
             Grid.Column="2" Grid.Row="3"
             Text="Binding ParentSurname"
             Width="Binding ElementName=ParentSurnameWaterMark,
                Path=Width"
             Style="StaticResource BasicTextBoxTextStyle"
             Background="Transparent">
    </TextBox>

    <!--Student Details TextBoxes-->
    <TextBlock x:Name="AgeWaterMark"           
               Grid.Column="5"
               Text="x:Static p:Resources.Age"
               Style="StaticResource WaterMarkStyle"
               Visibility="Binding 
                      ElementName=AgeContentTextBox, 
                      Path=Text.IsEmpty, Converter=StaticResource 
                      WaterMarkRemover"/>
    <TextBox x:Name="AgeContentTextBox"
             Grid.Column="5"
             Text="Binding Age"
             Width="Binding ElementName=AgeWaterMark,
                Path=Width"
             Style="StaticResource BasicTextBoxTextStyle"
             Background="Transparent"/>

    <Grid Grid.Column="5" Grid.Row="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBlock x:Name="GradeNumberWaterMark"
                       Text="x:Static p:Resources.GradeNumber"
                       Style="StaticResource GradeWaterMarkStyle"
                       Visibility="Binding 
                            ElementName=GradeNumberContentTextBox, 
                            Path=Text.IsEmpty, Converter=StaticResource 
                            WaterMarkRemover"/>
            <TextBox x:Name="GradeNumberContentTextBox"
                     Width="Binding ElementName=GradeNumberWaterMark,
                        Path=Width"
                     Text="Binding ClassNumber"
                     Style="StaticResource TextBoxTextStyle"
                     Background="Transparent"/>
        </Grid>
        <Grid Grid.Column="5">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBlock x:Name="GradeLetterWaterMark"
                       Text="x:Static p:Resources.GradeLetter"
                       Style="StaticResource GradeWaterMarkStyle"
                       Visibility="Binding 
                            ElementName=GradeLetterContentTextBox, 
                            Path=Text.IsEmpty, Converter=StaticResource 
                            WaterMarkRemover"/>
            <TextBox x:Name="GradeLetterContentTextBox"
                     Width="Binding ElementName=GradeLetterWaterMark,
                        Path=Width"
                     Text="Binding ClassLetter"
                     Style="StaticResource TextBoxTextStyle"
                     Background="Transparent"/>
        </Grid>
    </Grid>

    <TextBlock x:Name="NumberWaterMark"
               Grid.Column="5" Grid.Row="2"
               Text="x:Static p:Resources.NumberInClass"
               Style="StaticResource WaterMarkStyle"
               Visibility="Binding
                    ElementName=NumberContentTextBox, 
                    Path=Text.IsEmpty, Converter=StaticResource 
                    WaterMarkRemover"/>
    <TextBox x:Name="NumberContentTextBox"
             Grid.Column="5" Grid.Row="2"  
             Width="Binding ElementName=NumberWaterMark,
                    Path=Width"
             Text="Binding Number"
             Style="StaticResource BasicTextBoxTextStyle"
             Background="Transparent"/>

    <TextBlock x:Name="BarcodeWaterMark"
               Grid.Column="5" Grid.Row="3"
               Text="x:Static p:Resources.Barcode"
               Style="StaticResource WaterMarkStyle"
               Visibility="Binding
                    ElementName=BarcodeContentTextBox, 
                    Path=Text.IsEmpty, Converter=StaticResource 
                    WaterMarkRemover"/>
    <TextBox x:Name="BarcodeContentTextBox"
             Grid.Column="5" Grid.Row="3"
             Width="Binding ElementName=BarcodeWaterMark,
                    Path=Width"
             Text="Binding Barcode"
             Style="StaticResource BarcodeTextBoxTextStyle"
             Background="Transparent"/>

    <!--Buttons-->
    <Grid Grid.Row="4" Grid.ColumnSpan="6">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Button Grid.Row="1"
                Content="x:Static p:Resources.Add"
                HorizontalAlignment="Left"
                Style="StaticResource ButtonStyle"
                Command="Binding NewStudentCommand"/>
        <Button Grid.Column="2"
                Content="x:Static p:Resources.Clear"
                HorizontalAlignment="Right"
                Style="StaticResource ButtonStyle"/>
    </Grid>
</Grid>

这里是 ShowView

<Grid>
    <!--DataContext-->
    <Grid.DataContext>
        <dc:UserDummyData/>
    </Grid.DataContext> 
    <!--DataGrid-->         
    <DataGrid AutoGenerateColumns="False"
          CanUserAddRows="True"
          CanUserDeleteRows="True"
          ItemsSource="Binding FakeStudentDataLayer">
        <DataGrid.Columns>
            <DataGridTextColumn Header="x:Static p:Resources.sName"
                                Binding="Binding Name"/>
            <DataGridTextColumn Header="x:Static p:Resources.sSurname"
                                Binding="Binding Surname"/>
            <DataGridTextColumn Header="x:Static p:Resources.sAge"
                                Binding="Binding Age"/>
            <DataGridTextColumn Header="x:Static p:Resources.sGrade"
                                Binding="Binding Class"/>
            <DataGridTextColumn Header="x:Static p:Resources.sNumber"
                                Binding="Binding Number"/>
            <DataGridTextColumn Header="x:Static p:Resources.LastCheckIn"
                                Binding="Binding LastCheckIn"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

注意:如果我将 ShowView 中的代码放在 AddView 中,那么一切正常,但如果它们是这样的 - 一个两个单独的视图,DataGrid 不会更新。

编辑:我尝试使用相同的结构制作一个更简单的项目。令人难以置信的是它起作用了,我没有做任何不同的事情。新的采样器项目和这个项目之间的区别在于我使用了更基本的模型——只有两个属性。如果这很重要,我没有本地化。所以我的问题是为什么它适用于一个较小的项目而不是这个项目。

【问题讨论】:

通过使用ObservableCollection 和数据绑定,每当从集合中添加或删除项目时,UI 应该会自动更新。那么,问题是什么?发布一些显示实际问题的相关代码 这是什么平台? WPF、winform、ASP.NET 还是其他? @har07 是的,当我使用相同的视图添加和显示集合中的对象时,它会更新,但正如我所说,我有两个视图,一个用于添加,一个用于显示数据 @Gorge - 只要您添加到相同的ObservableCollection 并使用相同的实例完成绑定,视图就会更新。如果不是,请发布相关代码,以便任何人都可以帮助您。 【参考方案1】:

强制更新到底是什么意思?如果您的意思是添加数据,请尝试使用脚手架

http://www.asp.net/visual-studio/overview/2013/aspnet-scaffolding-overview

【讨论】:

我使用的是 WPF 而不是 ASP.NET 我认为这对我没有多大帮助【参考方案2】:

我不确定您的代码看起来如何,但我认为您有一个包含多个视图的窗口,例如,您的窗口有一个 MainViewModel,里面的视图有自己的视图模型。 如果 MainViewModel 创建并处理其他视图,那么它会获得它们的实例,并能够在那里调用方法。

所以也许您的问题是您想知道如何在视图模型之间进行通信?

这是我所想的一个小例子。 如果你有一个 MainViewModel、一个 DataAddViewModel 和一个 ShowViewModel。 MainViewModel 创建 DataAddViewModel 和 ShowViewModel。 DataAddViewModel 有一个事件,在插入新数据时触发。 ShowViewModel 具有与 Listview 或其他内容的绑定,以及触发该绑定的公共方法。

注意:以下仅为示例。

DataAddViewModel 中的可能事件

public event EventHandler DataAddedEvent;

private void RaiseDataAddedEvent()

    var handler = this.DataAddedEvent;
    if (handler == null) return;
    handler(this, EventArgs.Empty);

MainViewModel中可能的事件注册和处理

var _ShowVm = new ShowViewModel();
var _AddVm = new DataAddViewModel();
_addVm.DataAddedEvent += OnDataAdded;

//Notify our ShowViewModel about the new data
private void OnDataAdded(object sender, EventArgs e)

        _ShowVm.DataAdded();

ShowViewModel 中的公共方法

public void DataAdded()
    RaisePropertyChanged("NameOfMyBinding");

【讨论】:

看看我的代码。我会看看我是否可以将它添加到我的项目中 看起来您只有一个视图模型用于两个视图。也许您使用两个 dummydata 实例。因此,如果您添加数据,则仅将其添加到添加数据正在使用的实例中。编辑:当您将数据添加到集合时,您也不会引发属性更改事件。为此,您必须注册 ObservableCollection 的 CollectionChanged 事件。当您添加或删除集合的元素时会触发该事件 我没有故意创建视图实例,所以可以直接访问 DummyData 视图模型还是必须使用实例。你能告诉我如何使用 CollectionChanged 事件 据我所知,如果您像以前那样在 xaml 中设置数据上下文,它会自动创建它的一个实例。在您的情况下,这意味着您有两个 dummydata 实例。想想我在主视图模型中实例化视图模型的方法,并将它们的数据上下文设置为相同的 dummydata 实例。 好吧,如果你是对的,那为什么当我创建一个示例项目并做同样的事情时,视图会得到通知【参考方案3】:

我最好的猜测是问题出在您使用UserDummyData 的两个单独实例。在 Show 视图和 Add 视图中,您可以像这样设置 DataContext

<Grid.DataContext>
    <dc:UserDummyData/>
</Grid.DataContext> 

这两行都构造了一个新的UserDummyData 对象。因此,当您将数据添加到其中一个时,数据不会添加到另一个中。你应该这样做:

<Grid ... DataContext="x:Static p:Resources.MyUserDummyDataInstance"/>

然后,当您将学生添加到 UserDummyData 时,两个视图都会显示新学生,因为他们的两个列表(实际上是同一个列表)都将包含新学生。

【讨论】:

以上是关于如何强制更新视图的主要内容,如果未能解决你的问题,请参考以下文章

如何强制重绘列表视图?

如何以编程方式强制 EGORefreshTableHeaderView 更新

强制更新子视图控制器的 safeAreaInsets

vue 强制更新视图(视图不跟新的解决方案)

从 .xib 强制更新显示视图控制器

如何强制视图呈现自己?