选项卡控件中的MVVM列表框未更新

时间:2016-01-03 10:30:22

标签: c# wpf mvvm listbox

我正在努力解决更新问题。我有一个标签控件,列表框绑定到一个Observable Collection

ListBox HorizontalAlignment="Center" Height="450" VerticalAlignment="Top" Width="250"
     x:Name="LbxMenu" Background="{x:Null}" BorderBrush="{x:Null}" 
     ItemsSource="{Binding TestListsNames}" FontFamily="Segoe UI Semilight" FontSize="18"/>

查看模型:

    private ObservableCollection<string> _testListsName;

    public ObservableCollection<string> TestListsNames
    {
        get { return _testListsName; }
        set{ _testListsName = value; }
   }

在将实体插入数据库后,有一个事件在我的ViewModel中调用TestListInitialize方法,该方法应该刷新集合,它可以在调试器中看到它。但是listbox没有刷新,我必须重新启动应用程序才能看到更改。 它在单独的窗口中工作得很好但是当我将ui更改为制表符控件时却没有。

更新功能:

private void TestListNamesInitialize()
    {
        TestListsNames = db.GetTestListNamesFromDatabase();
        if (TestListsNames.Count != 0) CanLoad = true;           

    }

初始窗口:

<Controls:MetroWindow
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="Test.View.InitialWindow"
    xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
    xmlns:tabdata="clr-namespace:Test.View.TabItems"

    Title="Testownik" Height="600" Width="900" ShowTitleBar="True" ResizeMode="NoResize" Icon="../GraphicResources/Icon.ico">


<Controls:MetroWindow.RightWindowCommands>
    <Controls:WindowCommands>
        <Button Content="settings" />
        <Button>
            <StackPanel Orientation="Horizontal">
                <TextBlock Margin="4 0 0 0"
               VerticalAlignment="Center"
               Text="about" />
            </StackPanel>
        </Button>
    </Controls:WindowCommands>
</Controls:MetroWindow.RightWindowCommands>
<Controls:MetroAnimatedTabControl x:Name ="MainTabControl">
    <TabItem Header="Learn" Width="280">
        <tabdata:LearnTabItem/>
    </TabItem>
    <TabItem Header="Database" Width="280">
        <tabdata:DatabaseTabItem/>
    </TabItem>
    <TabItem Header="Statistics" Width="299">
        <tabdata:StatisticsTabItem/>
    </TabItem>
</Controls:MetroAnimatedTabControl>

代码背后:

    public partial class InitialWindow : MetroWindow
{
    InitialWindowViewModel viewModel=new InitialWindowViewModel();
    public InitialWindow()
    {
       InitializeComponent();
       DataContext = viewModel;
    }
}

}

DatabaseTabItem:

<UserControl x:Class="Test.View.TabItems.DatabaseTabItem"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
         xmlns:tabData="clr-namespace:Test.View.TabItems"
         Height="500" Width="900" Background="White" BorderBrush="Transparent">
<UserControl.Resources>


</UserControl.Resources>
<Grid>

    <Controls:MetroAnimatedTabControl x:Name ="DatabaseTabControl" Grid.Column="0" TabStripPlacement="Left" >
        <TabItem Header="Choose" Width="250" >
            <tabData:ChooseFromDbTabItem/>
        </TabItem>
        <TabItem Header="Add" Width="250">
            <tabData:AddToDbTabItem/>
        </TabItem>
        <TabItem Header="Remove" Width="250">
            <tabData:DeleteFromDbTabItem/>
        </TabItem>
    </Controls:MetroAnimatedTabControl>
</Grid>

代码背后的代码:

    DatabaseViewModel vm = new DatabaseViewModel();
    public DatabaseTabItem()
    {
        InitializeComponent();
        DataContext = vm;
    }

}

ChooseFromDbTabItem:

<UserControl x:Class="Test.View.TabItems.ChooseFromDbTabItem"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:Test.View.TabItems"
         xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"

         mc:Ignorable="d" 
         d:DesignHeight="500" d:DesignWidth="650" Background="White" BorderBrush="Transparent">

<Grid>
    <ListBox HorizontalAlignment="Center" Height="450" VerticalAlignment="Top" Width="250"
     x:Name="LbxMenu" Background="{x:Null}" BorderBrush="{x:Null}" 
     ItemsSource="{Binding TestListsNames}" FontFamily="Segoe UI Semilight" FontSize="18"/>
</Grid>

代码背后的代码:

  public partial class ChooseFromDbTabItem : UserControl
{
    public ChooseFromDbTabItem()
    {
        InitializeComponent();
    }
}

2 个答案:

答案 0 :(得分:1)

使用属性设置器替换列表时,不会引发PropertyChanged事件。 Generelly,尝试将集合属性设置为只读,以降低这类错误的风险。相反,清除列表并重新填充它。这将确保通知视图有关任何更改。

public class ViewModel
{
    private readonly ObservableCollection<string> _testListsName;

    public ObservableCollection<string> TestListsNames
    {
        get { return _testListsName; }
    }

    private void TestListNamesInitialize()
    {
        _testListsName.Clear();
        foreach(string name in db.GetTestListNamesFromDatabase())
        {
            _testListsName.Add(name);
        }

        if (_testListsNames.Count != 0) CanLoad = true;
    }
}

但是,请注意,这将使用.Add()调用在每个项目上引发更改的事件。见这里:Can I somehow temporarily disable WPF data binding changes?

编辑:来自您更新的代码。还可以看出,您没有在ChooseFromDbTabItem上设置DataContext。您需要将DataContext属性绑定到公开集合的视图模型:

<TabItem Header="Choose" Width="250" >
    <tabData:ChooseFromDbTabItem DataContext="{Binding}" />
</TabItem>

答案 1 :(得分:1)

由于您更改整个集合而不是单个项目(如果您更改了通过Observable更新的单个项目),您必须升级PropertyChanged事件。

 private ObservableCollection<string> _testListsName;
    public ObservableCollection<string> TestListsNames
    {
        get { return _testListsName; }
        set
        {
            if (_testListsName != value)
            {
                _testListsName = value;
                NotifyPropertyChanged("TestListsNames");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string property)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }