【问题标题】:Binding a collection of data objects in a model to a group of controls in a view (WPF)将模型中的数据对象集合绑定到视图中的一组控件 (WPF)
【发布时间】:2011-07-22 08:50:10
【问题描述】:

我在这里提出的另一个 WPF 问题。

我目前有一种情况,我需要将模型中的数据对象ObservableCollection<T> 绑定到视图中的一组用户控件。数据对象的数量经常变化,我需要随着集合的变化动态地创建这些用户控件。当前代码如下所示:

private void viewModel_PropertyChanged( object sender, PropertyChangedEventArgs e )
{
    if( e.PropertyName.Equals( "SomeCollection" ) )
    {
        UpdateUI();
    }
}

private void UpdateUI()
{
    foreach( MyUserControl elem in _uiElements )
    {       
        elem.MouseLeftButtonDown -= elem_MouseLeftButtonDown;
        // more event handler unhooking
        _MyCanvas.Children.Remove( elem );
    }

    _uiElements.Clear();

    foreach( DataObj dataObj in ViewModel.DataObjects )
    {
        MyUserControl newElem = new MyUserControl();
        _uiElements.Add( newElem );

        fpv.MouseLeftButtonDown += fpv_MouseLeftButtonDown;
        // more event handler hookups
        newElem.DataObject = dataObj;       

        _MyCanvas.Children.Add( newElem );
        Point dest = dataObj.ScreenPoint;
        Canvas.SetLeft( newElem, dest.X );
        Canvas.SetTop( newElem, dest.Y );
    }
}        

因此,如您所见,我(在代码中)响应更改的属性并动态创建一组新的用户控件。当相应的数据对象被“移动”(它包含一个 Point 属性)、添加、创建或设置整个集合时,将调用此代码。问题是这可能需要一秒钟或更长时间(最坏的情况是 100 多个元素),这是不可接受的。控件本身很简单;只有一个网格和一个形状(椭圆)。

TLDR;


所以,我想我是在问是否有人遇到过类似的情况。动态创建控件以响应集合中的更改并在 UI 中添加/删除它们,类似于 ItemsSource 属性在 ComboBox、ListBox、DataGrid 等中的工作方式。问题是这些控件需要允许鼠标拖动和在画布中任意位置布局的区域。任何帮助表示赞赏,在此先感谢。

【问题讨论】:

    标签: c# wpf data-binding collections wpf-controls


    【解决方案1】:

    这正是 ItemsControl 的用途,但是当您需要使用 Canvas 并从数据中提取位置时,布局会出现一些问题。它并不复杂,但需要几个不同的部分才能正常工作。这是一个假设您的 ViewModel 是 DataContext 的快速示例:

    <ItemsControl ItemsSource="{Binding DataObjects}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Canvas.Left" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.ScreenPoint.X}" />
                <Setter Property="Canvas.Top" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.ScreenPoint.Y}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <!-- your UserControl goes here -->
                <Ellipse Fill="Red" Width="20" Height="20" ToolTip="{Binding ScreenPoint}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    

    您还需要确保您的 DataObjects 属性是 ObservableCollection,然后您将能够添加和删除对象并在 UI 中自动更新已更改的项目,从而帮助您提高刷新性能问题。

    【讨论】:

      【解决方案2】:

      为什么不使用带有 ItemTemplateSelector 的虚拟化 ItemsControl?如果控件很简单,应该可以为它们使用数据模板,因此无需创建用户控件。由于项目控件是虚拟化的,因此只会呈现可见项目,因此应该更快。

      【讨论】:

      • 这些对象布局在画布上,需要用户拖动。 ItemsControl 会支持这样的操作吗?我环顾四周,不太确定(而且我还不是 WPF 专家……)。谢谢,进一步研究。
      • 所以我认为虚拟化不会有帮助,因为所有元素总是可见的,但我会考虑对每个项目进行模板化,看看是否有帮助。谢谢,+1,我会告诉你进展如何。
      • 好吧,看来我无法绑定这些控件的位置,所以我可能又回到了开始的地方。
      猜你喜欢
      • 1970-01-01
      • 2018-10-25
      • 1970-01-01
      • 2011-09-06
      • 2011-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-19
      相关资源
      最近更新 更多