为什么不是';这个数据绑定不起作用

本文关键字:数据绑定 不起作用 为什么不 | 更新日期: 2023-09-27 18:29:01

所以我对WPF数据绑定是全新的,它很复杂。在这一点上,我试图创建一个预制测试项目的列表,并在按下按钮时将其显示在带有数据模板的列表框中。经过几个小时对教程和MSDN的困惑,这是我能想到的最好的。

我想列出的数据项来自:

class ListingItem
{
    private string title;
    private string user;
    private string category;
    //Dummy constructor for test purposes
    public ListingItem()
    {
        title = "TestTitle";
        user = "TestUser";
        category = "TestCatagory";
    }
}

快速而肮脏的列表创建者:

class ListMaker
{
    public static List<ListingItem> getListing()
    {
        List<ListingItem> listing = new List<ListingItem>();
        for(int i = 0; i <100; i++)
        {
            listing.Add(new ListingItem());
        }
        return listing;
    }
}

列表本身的XAML:

<ListBox x:Name="Listing">
<ListBox.ItemTemplate>
    <DataTemplate>
        <StackPanel Orientation="Vertical">
            <StackPanel Orientation="Horizontal">
                <TextBlock Foreground="Gray" Margin="25,0,0,0" Text="{Binding user}"/>
                <TextBlock Foreground="Gray" Margin="25,0,0,0" Text="{Binding category}"/>
            </StackPanel>
            <TextBlock Foreground="Black" Width="270" TextWrapping="Wrap" Text="{Binding title}"/>
        </StackPanel>
    </DataTemplate>
</ListBox.ItemTemplate>

最后,按钮点击事件,本应使魔术发生:

private void TabClickEvent(object sender, RoutedEventArgs e)
    {
        Listing.DataContext = RedditScanner.getListing();
    }

问题是,很明显,魔法并没有发生。没有错误或任何简单的事情,我只是按下按钮,看不到列表框有任何变化。有什么帮助吗?

为什么不是';这个数据绑定不起作用

您不能绑定到私有字段。我想,甚至连公共领域都没有。

使用属性:

class ListingItem
{
    //private string title;
    //private string user;
    //private string category;
    public string Title { get; set; }
    public string User { get; set; }
    public string Category { get; set; }
    //Dummy constructor for test purposes
    public ListingItem()
    {
        Title = "TestTitle";
        User = "TestUser";
        Category = "TestCatagory";
    }
}

对于完全数据绑定,您必须在ListingItem上实现INotifyPropertyChanged

魔法没有发生。没有错误或任何如此简单的事情,

在执行过程中,请密切关注"输出窗口"。报告了绑定错误。

对您的代码进行了一些小的更改,如下所述。


class ListingItem
    {
        public  string title { get; set; }
        public string user { get; set; }
        public string category { get; set; }
    
        //Dummy constructor for test purposes
        public ListingItem()
        {
            title = "TestTitle";
            user = "TestUser";
            category = "TestCatagory";
        }
    }
  • 在列表项类中,我将标题、用户和类别更改为属性(get;set;)。我还需要将它们公开,以便可以通过绑定访问它们

    class ListMaker
    {
        public static List getListing()
        {
            List listing = new List();
            for (int i = 0; i < 100; i++)
            {
                listing.Add(new ListingItem());
            }
            return listing;
        }
    }
  • ListMaker类没有更改

    public class CommandHandler : ICommand
    {
        private Action _action;
        private bool _canExecute;
        public CommandHandler(Action action, bool canExecute=true)
        {
            _action = action;
            _canExecute = canExecute;
        }
        public bool CanExecute(object parameter)
        {
            return _canExecute;
        }
        public event EventHandler CanExecuteChanged;
        public void Execute(object parameter)
        {
            _action();
        }
    }
  • 我引入了一个能够绑定按钮的新类。这种类如果比较常见

<Window x:Class="SimpleDatabinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewmodel="clr-namespace:SimpleDatabinding"
Title="MainWindow" Height="350" Width="525">

<Window.DataContext>
<viewmodel:MainWindowViewModel/>
</Window.DataContext>

<Grid>
<DockPanel>
<Button Command="{Binding FillListCommand}" DockPanel.Dock="Top">Fill List</Button>

<ListBox ItemsSource="{Binding Listing}" DockPanel.Dock="Top">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="Gray" Margin="25,0,0,0" Text="{Binding user}"/>
<TextBlock Foreground="Gray" Margin="25,0,0,0" Text="{Binding category}"/>
</StackPanel>
<TextBlock Foreground="Black" Width="270" TextWrapping="Wrap" Text="{Binding title}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</Grid>
</Window>

  • 注意添加了xmlns:viewmodel="clr-namespace:SimpleDatabinding"。SimpleDatabinding是项目的名称。它用于在下面的数据上下文中定位视图模型
  • Window.DataContext将WPF页面绑定到视图模型。我调用了我的类MainWindowViewModel(请参见下文)。这将自动创建视图模型的实例并将其绑定到窗口
  • 我引入了一个点击按钮。它绑定到一个命令FillListCommand。我将在下面的视图模型中对此进行定义
  • 我更新了ListBox上的ItemsSource,使其绑定到Listing属性
  • 除此之外,我觉得还是一样的

class MainWindowViewModel : INotifyPropertyChanged 
{
    public event PropertyChangedEventHandler PropertyChanged;
    public List Listing { get; set; }
    public CommandHandler FillListCommand { get; set; }
    public MainWindowViewModel()
    {
        FillListCommand = new CommandHandler(DoFillList);
    }
    public void DoFillList()
    {
        Listing = ListMaker.getListing();
        ProperyHasChanged("Listing");
    }
    private void ProperyHasChanged(string propertyName)
    {
        if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
   
}

  • 最后,在viewmodel类中,我实现了INotifyPropertyChanged接口。这是一种通知UI视图模型上的值已更改的机制。在大多数实现中,它被封装在某种ViewModel基类中,但我把它留在了中,以便您可以看到它
  • 如上所述,我将Listing变量转换为公共属性(get;set;),以便可以通过绑定访问它
  • 我创建了一个名为FillListCommandCommandHandler属性。这使用了上面的类。按钮绑定到此变量。视图模型的构造函数初始化并指向单击按钮时要调用的函数
  • 最后,在DoFillList函数中,我初始化了Listing,但我也使用通知让UI知道它已经更改

很抱歉写了这么多。希望这能有所帮助。我认为这和你以前的没有太大的不同。

不要忘记用适当的标记来装饰您的数据成员和服务方法。

这些短视频非常适合学习WCF:http://channel9.msdn.com/Shows/Endpoint?sort=rating#tab_sortBy_rating

我发现我的代码只有两个问题:

  1. 属性在ListingItem中设置为私有,HenkHolterman捕获(+1ed)

  2. 我没有在列表中的任何位置设置ItemSource。

我根本不需要做彼得·特伦里提到的任何其他事情。