简体   繁体   English

WPF ListBox不更新

[英]WPF ListBox Not updating

I searched in this forum but I was unable to find a solution for my specific scenario. 我在这个论坛中进行了搜索,但是找不到适合我特定情况的解决方案。

I`m trying to understand WPF and MVVM and I build a simple WPF for this. 我试图了解WPF和MVVM,为此我构建了一个简单的WPF。

My Data Model is (I Implemented INotifyPropertyChanged here and the constructor initializes all properties): 我的数据模型是(我在这里实现了INotifyPropertyChanged,并且构造函数初始化了所有属性):

namespace MyApp.ui.Models
{
    public class Server : INotifyPropertyChanged
    {
        private int id;
        public int ID
        {
            get { return id; }
            set { id = value; }
        }

        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; OnPropertyChanged(Name); }
        }

        private string ipAddress;
        public string IPAddress
        {
            get { return ipAddress; }
            set { ipAddress = value; OnPropertyChanged(IPAddress); }
        }

        public Server(int ServerID, string ServerName, string ServerIpAddress)
        {
            ID = ServerID;
            Name = ServerName;
            IPAddress = ServerIpAddress;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if(handler != null)
            {
                handler(this, new PropertyChangedEventArgs( propertyName ) );
            }
        }
    }
}

My ViewModel (used by WPF Code Behind): 我的ViewModel(由WPF后面的代码使用):

namespace MyApp.ui.ViewModels
{
    public class ServersViewModel
    {
        private ObservableCollection<Server> server;
        public ObservableCollection<Server> Servers
        {
            get { return server; }
            set { server = value; }
        }

        public ServersViewModel()
        {
            Servers = new ObservableCollection<Server>
            {
                new Server(001, "Server001", @"192.168.254.3"),
                new Server(002, "Server002", @"100.92.0.200"),
                new Server(003, "Server003", @"64.32.0.3"),
                new Server(004, "Server004", @"172.10.0.4"),
                new Server(005, "Server005", @"165.23.0.233"),
                new Server(006, "Server006", @"81.22.22.6"),
                new Server(007, "Server007", @"10.10.0.7")
            };
        }

        public void ChangeServerNames()
        {
            //Before Change
            foreach (var item in Servers)
            {
                MessageBox.Show(item.Name);
            }

            int count = 1000;

            foreach (var item in Servers)
            {
                item.Name = "Server" + count.ToString();
                count += 1000;
            }

            //After Change
            foreach (var item in Servers)
            {
                MessageBox.Show(item.Name);
            }
        }
    }
}

My WPF Main View (Main Menu) loads a Custom user control (ExplorerView) with the following XAML code (Contains a listbox and each listbox item contains 1 checkbox + image + textblock) 我的WPF主视图(主菜单)使用以下XAML代码加载了自定义用户控件(ExplorerView)(包含一个列表框,每个列表框项均包含1个复选框+图像+文本块)

<UserControl x:Class="MyApp.ui.Views.ExplorerView"
             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:MyApp.ui.Views"
             mc:Ignorable="d" 
             d:DesignHeight="400" d:DesignWidth="200">
    <Grid>
        <ListBox ItemsSource="{Binding Servers}" Margin="2">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <CheckBox VerticalContentAlignment="Center" Margin="4">
                        <StackPanel Orientation="Horizontal">
                            <Image Source="/resources/server64.png" Height="30" Margin="4"></Image>
                            <TextBlock Text="{Binding Name}"
                                   VerticalAlignment="Center" Margin="4"></TextBlock>
                        </StackPanel>
                    </CheckBox>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</UserControl>

Finally the MainView Code Behind loads the ServersViewModel so the ExplorerView Control can Bind the data. 最后,后面的MainView代码将加载ServersViewModel,以便ExplorerView控件可以绑定数据。

namespace MyApp.ui
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public ServersViewModel context { get; set; }

        public MainWindow()
        {
            InitializeComponent();

            context = new ServersViewModel();
            DataContext = context;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            context.ChangeServerNames();
        }
    }
}

That said, I have 2 Questions: 也就是说,我有2个问题:

1) As you can see, in the MainView I implemented a Button click event that calls into ServersViewModel.ChangeServerNames() Method. 1)如您所见,在MainView中,我实现了一个Button单击事件,该事件调用ServersViewModel.ChangeServerNames()方法。 The problem is that my TextBlock in ExplorerView Control does not show the updated data. 问题是我在ExplorerView Control中的TextBlock不显示更新的数据。

I ChangeServerNames() I also use a MessageBox to show the Values Before and After the change, and I see that the values are changing, not sure why the ListBox/TextBlock is not updating...!!! 我ChangeServerNames()我也使用MessageBox来显示更改前后的值,并且我看到值正在更改,不确定为什么ListBox / TextBlock不更新...! (I already tested many other possible solutions, but I can`t get it working...) (我已经测试了许多其他可能的解决方案,但是我无法使其正常工作...)

2) I read that the CodeBehind in MainView (and all other views) should only contain the InitializeComponent(); 2)我读到MainView(和所有其他视图)中的CodeBehind应该只包含InitializeComponent(); and "DataContext = context;" 和“ DataContext =上下文;” at Maximum... If that is true, where the Events for button clicks and others should be placed? 最大值...如果是这样,应该在单击按钮的事件和其他事件的位置放置?

Finally the code for the MainWindow XAML: 最后是MainWindow XAML的代码:

<Window
        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyApp.ui"
        xmlns:Views="clr-namespace:MyApp.ui.Views"
        x:Class="MyApp.ui.MainWindow"
        mc:Ignorable="d"
        Title="Server" MinHeight="720" MinWidth="1024"
        Height ="720" Width="1024">
    <Grid Margin="2">

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200" />
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height="41*"/>
            <RowDefinition Height="608*"/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>

        <GridSplitter Grid.Column="1" Grid.Row="1"
              HorizontalAlignment="Center"
              VerticalAlignment="Stretch"
              Background="Gray" 
              ShowsPreview="True"
              Width="4" Margin="0,2,0,4"
              />

        <Views:MenuView Grid.ColumnSpan="3"/>
        <Views:FooterView Grid.Row="2" Grid.ColumnSpan="3" />
        <Views:ExplorerView Grid.Column="0" Grid.Row="1" />

        <!--Temp Tests-->
        <StackPanel Margin="12" Grid.Column="3" Grid.Row="1" Width="Auto" Height="Auto" Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left">
            <Button Margin="4" Width="120" Height="30" Content="Change Data Test..." Click="Button_Click" />
        </StackPanel>

    </Grid>
</Window>

Thank you for your time... 感谢您的时间...

Ok, I found the problem... 好的,我发现了问题...

Instead of 代替

set { name = value; OnPropertyChanged(Name); }
set { ipAddress = value; OnPropertyChanged(IPAddress); }

I was missing the Quotesfor the String argument on method call The correct form is 我在方法调用中缺少Quotesfor the String参数正确的形式是

set { name = value; OnPropertyChanged("Name"); }
set { ipAddress = value; OnPropertyChanged("IPAddress"); }

Weird that the compiler didn`t throw any error.... The Method private void OnPropertyChanged(string propertyName) Is "Asking" for a string as input arg. 奇怪的是编译器没有抛出任何错误。...方法私有无效OnPropertyChanged(string propertyName)对于输入arg的字符串是“要求”。

AnyWay the best to avoid these errors (that I found) is to write the event like this (The caller supplies it`s own Public Name): 无论如何,避免这些错误(我发现)的最好方法是编写这样的事件(调用者提供它自己的公共名称):

private void OnPropertyChanged([CallerMemberName] String propertyName = "")
  {
    if (PropertyChanged != null)
    {
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}

Now I can do 现在我可以做

set { name = value; OnPropertyChanged(); }
set { ipAddress = value; OnPropertyChanged(); }

Thank you. 谢谢。

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

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