【问题标题】:Databinding to WrapPanel does not work as expected数据绑定到 WrapPanel 不能按预期工作
【发布时间】:2013-04-29 14:43:06
【问题描述】:

我正在尝试使用我自己的用户控件集合填充WrapPanel

儿童控制:

<UserControl x:Class="MyApplication.StockMappings.StockView"
             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" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid Width="140" Height="80">
        <Border CornerRadius="6" BorderBrush="Black" BorderThickness="2" >
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="0.6*"/>
                    <RowDefinition Height="0.4*"/>
                </Grid.RowDefinitions>
                <TextBlock Grid.Row="0" FontSize="18" FontWeight="Bold">
                    <Label Content="{Binding Path=ID}"/>
                </TextBlock>
                <TextBlock Grid.Row="1" FontSize="12" FontWeight="Bold">
                    <Label Content="{Binding Path=StockName}"/>
                </TextBlock>
            </Grid>
        </Border>
    </Grid>
</UserControl>

cs 文件:

namespace MyApplication.StockMappings
{
    /// <summary>
    /// Interaction logic for StockView.xaml
    /// </summary>
    public partial class StockView : UserControl
    {
        public StockView()
        {
            InitializeComponent();
        }

        public string ID
        {
            get;
            set;
        }

        public string StockName
        {
            get;
            set;
        }
    }
}

最后是带有环绕面板的窗口:

<Window x:Class="MyApplication.StockMappings.TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyApplication.StockMappings"
        Title="TestWindow" Height="300" Width="300">
    <Grid>
        <ItemsControl Name="Stocks" ItemsSource="{Binding AllStocks}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel Orientation="Horizontal"/>                        
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <local:StockView/>                                            
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>

又是 C# 代码:

public partial class TestWindow : Window
{
    public TestWindow()
    {
        InitializeComponent();
        var stocks = new[]
        {
            new StockView() { ID = "M0", StockName = "abc"},
            new StockView() { ID = "M1", StockName = "def"},
        };

        Stocks.DataContext = new Test()
        {
            AllStocks = stocks.ToList()
        }; 
    }
}

Test 类(子数据的容器)非常简单:

public class Test
{
    public List<StockView> AllStocks
    {
        get;
        set;
    }
}

最后,结果:

所有边框都是空白的。既不显示ID 也不显示StockName

我做错了什么?

我已经确认(通过添加一个虚拟属性)StockView 控件从 Test 对象中获取 ID 值,而不是从 AllStocks 列表中获取子项。但为什么?我没有定义ItemTemplate 吗?那它有什么用呢?

【问题讨论】:

  • What am I doing wrong? - 一切。 UI 不是存储数据的正确位置。创建一个适当的模型或视图模型来存储该数据并将您的控件绑定到该数据。还要让 UI 创建 UI,不要自己实例化 UI 元素。

标签: wpf data-binding mvvm wrappanel


【解决方案1】:

您缺少的是一个适当的视图模型项类来保存您的数据。这不应该与视图对象混淆,例如您的 StockView。

首先,从 StockView 控件中删除 IDStockName 属性。这些属性将移至数据项类。

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

其次,使用StockItem 数据项类和具有AllStocks 属性的ViewModel 类创建视图模型(或者像您已经做过的那样直接将其称为Test)。

public class StockItem
{
    public string ID { get; set; }
    public string StockName { get; set; }
}

public class ViewModel
{
    public ObservableCollection<StockItem> AllStocks { get; set; }
}

最后,将 MainWindow 的 DataContext 设置为 ViewModel 类的实例。

public MainWindow()
{
    InitializeComponent();

    var vm = new ViewModel { AllStocks = new ObservableCollection<StockItem>() };
    vm.AllStocks.Add(new StockItem { ID = "M0", StockName = "abc" });
    vm.AllStocks.Add(new StockItem { ID = "M1", StockName = "def" });

    DataContext = vm;
}

如果数据项在添加到AllStocks 集合后可以修改,则StockItem 类必须实现INotifyPropertyChanged 接口。

【讨论】:

  • 所有答案都很有用,但我接受这个作为最全面的答案。非常感谢
【解决方案2】:

好吧,StockView 用户控件的DataContext 应该是它自己的类后面的代码。

这应该可以正常工作!

public StockView()
{
    InitializeComponent();
    this.DataContext = this;
}

【讨论】:

    【解决方案3】:

    设置用户控件的数据内容 例如在代码中:

    public StockView()
            {
                InitializeComponent();
                DataContext = this;
            }
    

    【讨论】:

    • 我看到彼得更快 :-)
    【解决方案4】:

    DataTemplates 模板数据,您绑定到控件列表,ItemTemplate 将被忽略,因为可以直接添加控件,您应该在输出中收到关于此的警告。因此没有为UserControls 设置DataContext,您应该将属性从UserControl 移动到模型类并添加它的实例。另外我建议不要设置DataContextUserControl

    【讨论】:

      猜你喜欢
      • 2019-04-23
      • 1970-01-01
      • 2021-03-05
      • 1970-01-01
      • 1970-01-01
      • 2012-01-30
      • 1970-01-01
      • 1970-01-01
      • 2014-11-19
      相关资源
      最近更新 更多