1

所以我是 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();
    }

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

4

4 回答 4

2

您不能绑定到私有字段。我认为甚至没有到公共领域。

使用属性:

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";
    }
}

对于完整的数据绑定,您必须 INotifyPropertyChanged.ListingItem

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

在执行期间密切关注输出窗口。报告绑定错误。

于 2013-08-23T22:42:47.310 回答
1

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


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;),以便可以通过绑定访问它。
  • 我创建了一个名为FillListCommand的CommandHandler属性。这使用上面的类。按钮绑定到此变量。视图模型的构造函数初始化并将其指向单击按钮时要调用的函数。
  • 最后,在DoFillList函数中,我按照您的方式初始化列表,但我也使用通知让 UI 知道它已更改。

对不起所有的写作。希望这有点帮助。我不认为它与你所拥有的差别太大。

于 2013-08-24T01:00:09.953 回答
0

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

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

于 2013-08-23T23:37:05.167 回答
0

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

  1. 这些属性在 ListingItem 中设置为私有,Henk Holterman 抓住了(+1ed)

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

我根本不需要做 Peter Trenery 提到的任何其他事情。

于 2013-08-26T23:01:06.897 回答