【问题标题】:ItemsControl displaying class nameItemsControl 显示类名
【发布时间】:2017-08-25 21:09:36
【问题描述】:

此应用根据需要显示集合的类名,而不是文本框。我已经阅读了其他问题,但无法弄清楚我错过了什么。我有一个数据上下文,我作为一个项目源绑定到集合,并且我添加了一个项目。我想要的只是将我的视图模型'DrawBoxViewModel'中的集合'Boxes'绑定到项目源,并让它将单个项目显示为文本框。感谢所有帮助。

首先是我的 XAML:

<Page
x:Class="BoxMaker2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BoxMaker2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:BoxMaker2.ViewModels"
mc:Ignorable="d">

<Page.Resources>
    <vm:DrawBoxViewModel x:Key="DrawBoxViewModel"/>
</Page.Resources>
<Canvas DataContext="{Binding Source={StaticResource DrawBoxViewModel}}">
    <ItemsControl ItemsSource="{Binding Boxes}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Width="350" Height="600" Background="AliceBlue"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.Resources>
            <DataTemplate x:DataType="vm:Box" x:Key="test">
                <VariableSizedWrapGrid>
                    <TextBox Background="White" 
                             Text="{x:Bind Data}"
                             Width="100"
                             Height="100"/>
                    <VariableSizedWrapGrid.RenderTransform>
                        <TranslateTransform X="{Binding LeftCanvas}" Y="{Binding TopCanvas}"/>
                    </VariableSizedWrapGrid.RenderTransform>
                </VariableSizedWrapGrid>
            </DataTemplate>
        </ItemsControl.Resources>
    </ItemsControl>
</Canvas>

现在是我的视图模型:

namespace BoxMaker2.ViewModels
{
public class DrawBoxViewModel
{
    #region fields

    private ObservableCollection<Box> _boxes;

    #endregion

    #region properties

    public ObservableCollection<Box> Boxes { get { return this._boxes; } }

    #endregion

    #region constructors

    public DrawBoxViewModel()
    {
        this._boxes = new ObservableCollection<Box>();
        _boxes.Add(new Box() { Data = "hello!", LeftCanvas = 200, TopCanvas = 200 });
    }

    #endregion

}

public class Box : INotifyPropertyChanged
{
    private int _generation;
    public int Generation
    {
        get { return _generation; }
        set { _generation = value; OnPropertyChanged("Generation"); }
    }

    private int _childNo;
    public int ChildNo
    {
        get { return _childNo; }
        set { _childNo = value; OnPropertyChanged("ChildNo"); }
    }

    private Box _parentBox;
    public Box ParentBox
    {
        get { return _parentBox; }
        set { _parentBox = value; OnPropertyChanged("ParentBox"); }
    }

    private List<Box> _childrenBox;
    public List<Box> ChildrenBox
    {
        get { return _childrenBox; }
        set { _childrenBox = value; OnPropertyChanged("ChildrenBox"); }
    }

    private string _data;
    public string Data
    {
        get { return _data; }
        set
        {
            _data = value;
            OnPropertyChanged("Data");
        }
    }

    private double _topCanvas;
    public double TopCanvas
    {
        get { return _topCanvas; }
        set
        {
            _topCanvas = value;
            OnPropertyChanged("TopCanvas");
        }
    }

    private double _leftCanvas;
    public double LeftCanvas
    {
        get { return _leftCanvas; }
        set
        {
            _leftCanvas = value;
            OnPropertyChanged("LeftCanvas");
        }
    }

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

}

【问题讨论】:

    标签: c# uwp uwp-xaml


    【解决方案1】:

    我不确定您要达到的目标,但我在您的代码中发现了一些问题。

    1. 您应该将您的 VM 分配给 PageDataContext 直接。

      <Page.DataContext>
          <vm:DrawBoxViewModel />
      </Page.DataContext>
      

      完成此操作后,您现在可以从您的Canvas删除 DataContext="{Binding Source={StaticResource DrawBoxViewModel}}"

    2. &lt;ItemsControl.Resource&gt; 替换为 &lt;ItemsControl.ItemTemplate&gt; 并删除 x:Key="test",假设您要显示多个 用户界面上的TextBoxes。 DataTemplate 内的Resource 你 在您通过它的键引用它之前,定义不会做任何事情。我不 认为你真的想要这里。
    3. 您应该使用x:Bind 进行XY 绑定

      <TranslateTransform X="{x:Bind LeftCanvas}"
                          Y="{x:Bind TopCanvas}" />
      
    4. 您的Boxes 收藏可以简化如下

      #region properties
      
      public ObservableCollection<Box> Boxes { get; } = new ObservableCollection<Box>();
      
      #endregion
      
      #region constructors
      
      public DrawBoxViewModel()
      {
          Boxes.Add(new Box() { Data = "hello!", LeftCanvas = 0, TopCanvas = 200 });
      }
      
      #endregion
      

    希望这会有所帮助!

    【讨论】:

    • 0. OP 没有问什么是实现 MVVM 的正确方法。他问如何正确地显示集合中的元素。 1. 视图模型作为资源非常好。他通过 StaticResource 引用它,所以这很好。 2 他不需要 x:Bind 任何东西。这是用户的偏好。 3.你需要解释为什么复制WPF代码在UWP上不起作用。显然他正在查找不适用于 UWP 的 WPF 教程,很明显他是一个菜鸟。
    • @bleepzter 您应该始终将 DataContext 设置在顶层并让它向下流动。这是最佳实践。当您设置了 x:Bind all 以获得性能提升,并且您已经为 Data 属性这样做时,跳过这两个的原因是什么?
    • 你根据假设工作。所以首先 - 如果页面有其他设置数据上下文的东西,可能是在代码后面或其他方式?所以不要再做假设了。这是最佳实践,但最好将其作为最佳实践提出并解释原因。不要只命令 OP 他们应该或应该做什么。第二个 x:Bind 被编译,这对速度有好处,但与常规绑定相比,它也有限制。它们在 x:Bind 无法处理的某些情况下更合适。所以再一次,“应该”不是一个有效的词——“建议”更像是它,并解释原因。
    • @bleepzter 这两个都解决了我的问题。我最终使用了 Justin XL 解决方案,因为我认为它更简单,在资源中定义数据模板而不是在 itemtemplate 中定义是一个明显的错误。谢谢你们的意见。
    【解决方案2】:

    您的 Items 控件不知道要使用哪个数据模板。当前,您的视图模型有一个通过 x:DataType="vm:Box" 关联的模板,该模板被定义为项目控件中的资源。

    问题在于通用 Windows 平台无法识别与数据类型关联的模板。所以即使有模板,控件在渲染视图模型集合时也不知道如何找到它。

    基于绑定类型的模板自动解析是 WPF 的一项功能,在 UWP 中不可用。

    这意味着在 WPF 中,您可以通过数据模板的 x:DataType="Object Type" 属性将数据模板与类/对象相关联(这就是您所做的)。当集合被绑定时,渲染引擎会自动将集合中的各个项目与其各自的模板进行匹配。

    这非常强大,因为如果您的集合有许多不同类型的盒子(或从 DrawBoxViewModel 继承的东西),您可以通过简单地定义一个模板来以不同的方式呈现每个项目类型。好吧,这不再是了。微软在 UWP 中破坏了该功能。

    长话短说 - 将模板移至页面资源集合。给它一个键,例如:

    <Page.Resources>
       <vm:DrawBoxViewModel x:Key="DrawBoxViewModel"/>
       <DataTemplate x:Key="test">
          <VariableSizedWrapGrid>
              <TextBox Background="White" 
                  Text="{x:Bind Data}"
                  Width="100"
                  Height="100"/>
                 <VariableSizedWrapGrid.RenderTransform>
                    <TranslateTransform X="{Binding LeftCanvas}" Y="{Binding TopCanvas}"/>
                 </VariableSizedWrapGrid.RenderTransform>
            </VariableSizedWrapGrid>
         </DataTemplate>
    </Page.Resources>
    

    在您的项目控件中引用模板,如下所示: &lt;ItemsControl ItemsSource="{Binding Boxes} ItemTemplate={StaticResource test} "&gt;

    【讨论】:

    • 但不能像 WPF 中那样自动解析模板。
    • 是的,但它被用作 WPF。
    • 不,不是。它在 UWP 中的用途完全不同。
    猜你喜欢
    • 1970-01-01
    • 2011-09-14
    • 1970-01-01
    • 1970-01-01
    • 2015-08-09
    • 2018-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多