将模型中的一组数据对象绑定到视图中的一组控件 (WPF)

发布于 2024-10-26 11:12:24 字数 1446 浏览 1 评论 0原文

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

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

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

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

太长了;


所以想问问大家有没有遇到过类似的情况。动态创建控件以响应集合中的更改,并从 UI 中添加/删除它们,类似于 ItemsSource 属性在 ComboBox、ListBox、DataGrid 等中的工作方式。问题是这些控件需要允许鼠标拖动以及在画布中的任意位置布置区域。感谢任何帮助,提前致谢。

another WPF question from me here.

I currently have a situation in which I need to bind an ObservableCollection<T> of data objects in a model to a group of UserControls in a view. The number of data objects changes often, and I need to create these UserControls on the fly as the collection changes. The current code looks something like this:

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

So, as you can see, I respond (in code) to a property changed and dynamically create a group of new UserControls. This code is called when a corresponding data object is "Moved" (it contains a Point property), added, created, or the entire collection is set. The problem is that this can take (worst case with 100+ elements) one second or more, which is unacceptable. The controls themselves are simply; only a grid and a shape (Ellipse).

TLDR;


So, I suppose I'm asking if anyone out there has come across a similar situation. Dynamically creating controls in response to a change in a collection and adding/removing them from the UI, similar to how the ItemsSource property works in a ComboBox, ListBox, DataGrid, whatever. The catch is that these controls need to allow for mouse dragging and area laid out in arbitrary locations in a Canvas. Any help is appreciated, thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

失而复得 2024-11-02 11:12:24

为什么不将虚拟化 ItemsControl 与 ItemTemplateSelector 一起使用?如果控件很简单,则应该可以使用数据模板,因此无需创建用户控件。由于项目控件是虚拟化的,因此只会渲染可见项目,因此速度应该更快。

Why don't you use a virtualized ItemsControl with an ItemTemplateSelector? If the controls are simple it should be possible to use datatemplates for them so no need to create user controls. Since the items control is virtualized only the visible items will be rendered so should be faster.

糖粟与秋泊 2024-11-02 11:12:24

这正是 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 中自动更新所需要的项目。已更改,有助于解决刷新性能问题。

This is exactly what ItemsControl is for but there are a few wrinkles with layout when you need to use a Canvas and pull the positions from the data. It's not complicated but needs a few different parts to work correctly. Here's a quick sample assuming your ViewModel is the 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>

You're also going to want to make sure your DataObjects property is an ObservableCollection and you will then be able to add and remove objects and get automatic updates in the UI of just the items that have changed, helping with your refresh performance problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文