【问题标题】:WPF / XAML: Data Binding for UserControlsWPF / XAML:用户控件的数据绑定
【发布时间】:2018-09-07 11:05:28
【问题描述】:

所以我正在创建“卡片”以直观地表示 StackPanel 中的一组对象(我使用列表来保存这些对象):

主窗口 XAML:

<Window /* ... */>
    <StackPanel x:Name="Deck" Orientation="Horizontal" />
</Window>

主窗口 C#:

public partial class MainWindow : Window
{
    /* ... */
    private void OnDataReceived(List<Reading> readings)
    {
        foreach(Reading r in readings)
        {
            Deck.Children.Add(new Card
            {
                Id = r.Id,
                Value = r.Value
            });
        }
    }
}

用户控件 XAML:

<UserControl /* ... */ x:Name="crd">
    <Label Content="{Binding Path=Id, ElementName=crd}" />
    <Label Content="{Binding Path=Value, ElementName=crd} />
</UserControl>

用户控件 C#:

public partial class LoggerRepresentation : UserControl
{
    public string Id { get; set; }
    public int Value { get; set; }
    /* ... */
}

在向Deck.Children 添加一个元素后,它的视觉表示确实会按预期出现在 StackPanel 中。但是,DP 似乎缺少一些东西,因为绑定 IdValue 的标签仍然为空。

(将x:Name="crd" 提供给我的UserControl,然后在绑定中使用它作为ElementName 的想法已从the answer to a seemingly related question 插入,但在这种情况下可能会产生误导。)

【问题讨论】:

  • 看起来你正在做的事情就像它曾经在 Windows 编程中那样。你应该检查 MVVM 和 INotifyPropertyChanged 接口。

标签: c# wpf xaml data-binding


【解决方案1】:

当你想显示一个动态的项目集合时,你应该使用ItemsControl

将 XAML 标记中的 StackPanel 替换为 ItemsControl

<ItemsControl ItemsSource="{Binding Cards}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <local:LoggerRepresentation />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

直接绑定到UserControl中对应Card对象的源属性(并将Label元素替换为TextBlocks):

<TextBlock Text="{Binding Path=Id}" />
<TextBlock Text="{Binding Path=Value} />

创建一个视图模型类,该类通过公共属性公开Card 对象的集合,并将您的应用程序逻辑移至该类:

public class ViewModel
{
    public ObservableCollection<Card> Cards { get; } = new ObservableCollection<Card>();

    //...
    private void OnDataReceived(List<Reading> readings)
    {
        foreach (Reading r in readings)
        {
            Cards.Add(new Card
            {
                Id = r.Id,
                Value = r.Value
            });
        }
    }
}

将定义ItemsControl的视图的DataContext设置为视图模型类的实例:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new ViewModel();
    }
}

这种设计模式被称为模型-视图-视图模型 (MVVM),它是在开发基于 XAML 的 UI 应用程序时使用的推荐模式。如果您使用 Google,您会发现更多内容可供阅读和了解。

【讨论】:

  • &lt;local:LoggerRepresentation /&gt; 不允许在 &lt;ItemsControl.ItemTemplate&gt; 中,但是当我将模板标签包装在 &lt;DataTemplate&gt; 中时被接受。对吗?
  • 我似乎还是弄错了,至少我现在的输出有错误:System.Windows.Data Error: 40 : BindingExpression path error: 'Value' property not found on 'object' ''ViewModel' (HashCode=20770076)'. BindingExpression:Path=Value; DataItem='ViewModel' (HashCode=20770076); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')&lt;ItemsControl ItemsSource="{Binding Cards}"&gt; 中的“卡片”@ 引用公共的“卡片”ObservableCollection&lt;Card&gt; Cards { get; } = new ObservableCollection&lt;Card&gt;(); ?这仍然超出了我的范围
  • 它应该,除非你在某处覆盖 DataContext。
  • 我现在如何理想地从 MainWindow 将项目添加到列表中?我在 ViewModel 类中添加了一个函数“Add()”,并且只是将接收到的项目路由到 Cards 属性中。对吗?
  • 你应该使用命令。但那是另一回事了。如果您还有其他问题,请提出新问题。
猜你喜欢
  • 1970-01-01
  • 2012-04-15
  • 2011-08-11
  • 1970-01-01
  • 2011-04-01
  • 1970-01-01
  • 2012-06-28
相关资源
最近更新 更多