Silverlight 数据绑定、可观察集合和用户控件

发布于 2024-12-04 21:43:33 字数 4555 浏览 3 评论 0原文

我遇到了似乎无法解决的数据绑定问题。 (警告:下面的完整代码示例)

我正在开发一个分组控件,它能够将不同的项目分组到命名组中。我有一个定义此设置的数据模型,该设置具有可观察的组集合,并且每个组都有一个可观察的项目集合:

  public class GroupingModel
  {
    public ObservableCollection<Group> Groups { get; set; }
    public GroupingModel()
    {
      Groups = new ObservableCollection<Group>();
    }

    public void RegroupItem(Item item)
    {
      var containingGroup = Groups.FirstOrDefault(x => x.Items.Contains(item));
      if (containingGroup == null ||
        item.GroupName == containingGroup.GroupName)
        return;


      containingGroup.Items.Remove(item);

      var newGroup = Groups.FirstOrDefault(x => x.GroupName == item.GroupName);
      if (newGroup == null)
      {
        newGroup = new Group()
        {
          GroupName = item.GroupName
        };
        newGroup.Items.Add(item);
        Groups.Add(newGroup);
      }
      else
      {
        newGroup.Items.Add(item);
      }
    }
  }

  public class Group
  {
    public ObservableCollection<Item> Items { get; set; }
    public string GroupName { get; set; }
    public Group()
    {
      Items = new ObservableCollection<Item>();
    }
  }

  public class Item
  {
    public string GroupName { get; set; }
    public string Title { get; set; }
    public object Content { get; set; }
  }

此数据模型已填充并绑定到 DataContext:

  public partial class MainPage : UserControl
  {
    public MainPage()
    {
      InitializeComponent();

      SetupModel();
    }

    private GroupingModel m_model = new GroupingModel();

    private void SetupModel()
    {
      var group = new Group()
                    {
                      GroupName = "Default",
                    };
      for (int i = 0; i < 5; i++)
      {
        Item item = new Item()
                      {
                        Title = "Item " + i,
                        GroupName = "Default",
                        Content = new TextBlock
                                    {
                                      Text = "Hello: " + i,
                                    }
                      };
        group.Items.Add(item);
      }
      m_model.Groups.Add(group);

      DataContext = m_model;
    }

    private void movegroup(object sender, RoutedEventArgs e)
    {
      var firstGroup = m_model.Groups.First();
      var item = firstGroup.Items.FirstOrDefault();
      if (item != null)
      {
        item.GroupName = "NewGroup";
        m_model.RegroupItem(item);
      }
    }
  }

最后,我在 XAML 中绑定整个内容,如下所示

<UserControl x:Class="ObservableCollectionBinding.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit" >
  <Grid x:Name="LayoutRoot">
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Button Content="Move first to new group" Click="movegroup" />

    <ItemsControl ItemsSource="{Binding Groups}" Grid.Row="1">
      <ItemsControl.ItemTemplate>
        <DataTemplate>
          <StackPanel Orientation="Vertical">
            <TextBlock FontWeight="ExtraBlack" Text="{Binding GroupName}" Margin="0,2,0,2" />

            <ItemsControl ItemsSource="{Binding Items}">
              <ItemsControl.ItemTemplate>
                <DataTemplate>
                  <toolkit:Expander Header="{Binding Title}" Content="{Binding Title}">
                    <!--Content="{Binding Content}"-->
                  </toolkit:Expander>
                </DataTemplate>
              </ItemsControl.ItemTemplate>
            </ItemsControl>
          </StackPanel>
        </DataTemplate>
      </ItemsControl.ItemTemplate>
    </ItemsControl>
  </Grid>
</UserControl>

:按钮 我通过从可观察项目集合中删除、创建新组、在该组中插入项目并将新组添加到可观察组集合中,将第一个项目从默认组移动到新组中。当 Expander 中的 Content 属性绑定到 Title 属性时,此功能可以正常工作。您可以展开和关闭项目并将它们全部移至新组。

但是,如果我将其更改为绑定到 Content 属性(上面注释掉的行,它绑定到在代码隐藏中创建的 TextBlock),则绑定一开始就可以正常工作(可以打开和关闭扩展器,显示 TextBlock),但是如果您尝试移动已展开的项目,应用程序将终止并显示 ArgumentException 和消息“值不在预期范围内”。

我是否试图做一些不受支持的事情(将内容绑定到在代码隐藏中创建的用户控件),我是否设置了错误的绑定或者其他错误。

注意:我真的希望绑定能够与在代码隐藏中创建的用户控件一起使用,因为为我们的特定用户控件创建完整的数据绑定模型将是一项相当大的任务。

I've run into a data binding issue that I cannot seem to resolve. (Warning: full code sample below)

I am developing a grouping control that is able to group different items into named groups. I have a data model that defines this setup that have an observablecollection of groups and each group have an observablecollection of items:

  public class GroupingModel
  {
    public ObservableCollection<Group> Groups { get; set; }
    public GroupingModel()
    {
      Groups = new ObservableCollection<Group>();
    }

    public void RegroupItem(Item item)
    {
      var containingGroup = Groups.FirstOrDefault(x => x.Items.Contains(item));
      if (containingGroup == null ||
        item.GroupName == containingGroup.GroupName)
        return;


      containingGroup.Items.Remove(item);

      var newGroup = Groups.FirstOrDefault(x => x.GroupName == item.GroupName);
      if (newGroup == null)
      {
        newGroup = new Group()
        {
          GroupName = item.GroupName
        };
        newGroup.Items.Add(item);
        Groups.Add(newGroup);
      }
      else
      {
        newGroup.Items.Add(item);
      }
    }
  }

  public class Group
  {
    public ObservableCollection<Item> Items { get; set; }
    public string GroupName { get; set; }
    public Group()
    {
      Items = new ObservableCollection<Item>();
    }
  }

  public class Item
  {
    public string GroupName { get; set; }
    public string Title { get; set; }
    public object Content { get; set; }
  }

This datamodel is populated and bound to the DataContext:

  public partial class MainPage : UserControl
  {
    public MainPage()
    {
      InitializeComponent();

      SetupModel();
    }

    private GroupingModel m_model = new GroupingModel();

    private void SetupModel()
    {
      var group = new Group()
                    {
                      GroupName = "Default",
                    };
      for (int i = 0; i < 5; i++)
      {
        Item item = new Item()
                      {
                        Title = "Item " + i,
                        GroupName = "Default",
                        Content = new TextBlock
                                    {
                                      Text = "Hello: " + i,
                                    }
                      };
        group.Items.Add(item);
      }
      m_model.Groups.Add(group);

      DataContext = m_model;
    }

    private void movegroup(object sender, RoutedEventArgs e)
    {
      var firstGroup = m_model.Groups.First();
      var item = firstGroup.Items.FirstOrDefault();
      if (item != null)
      {
        item.GroupName = "NewGroup";
        m_model.RegroupItem(item);
      }
    }
  }

Finally I am binding the whole thing in XAML as shown below:

<UserControl x:Class="ObservableCollectionBinding.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit" >
  <Grid x:Name="LayoutRoot">
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Button Content="Move first to new group" Click="movegroup" />

    <ItemsControl ItemsSource="{Binding Groups}" Grid.Row="1">
      <ItemsControl.ItemTemplate>
        <DataTemplate>
          <StackPanel Orientation="Vertical">
            <TextBlock FontWeight="ExtraBlack" Text="{Binding GroupName}" Margin="0,2,0,2" />

            <ItemsControl ItemsSource="{Binding Items}">
              <ItemsControl.ItemTemplate>
                <DataTemplate>
                  <toolkit:Expander Header="{Binding Title}" Content="{Binding Title}">
                    <!--Content="{Binding Content}"-->
                  </toolkit:Expander>
                </DataTemplate>
              </ItemsControl.ItemTemplate>
            </ItemsControl>
          </StackPanel>
        </DataTemplate>
      </ItemsControl.ItemTemplate>
    </ItemsControl>
  </Grid>
</UserControl>

When pressing the button I move the first item from the default group into a new group by removing from the observable item collection, creating a new group, inserting the item in this group and adding the new group to the observable collection of groups. This work correctly when the Content property in the Expander is bound to the Title property. You can expand and close items and move them all to the new group.

However, if I change this to bind to the Content property (the line commented out above, which binds to the TextBlock that is created in codebehind) the binding works fine to start with (expanders can be opened and closed, TextBlock is shown) but if you try to move an item that has been expanded, the application dies with an ArgumentException and a message 'Value does not fall within the expected range'.

Am I trying to do something that is not supported (binding the content to a usercontrol created in codebehind), am I setting binding up incorrectly or is something else wrong.

NOTE: I am really hoping to get the binding to work with a usercontrol created in codebehind, since creating a full databinding model for our specific usercontrol would be a quite large undertaking.

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

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

发布评论

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

评论(1

柳若烟 2024-12-11 21:43:33

好吧,没有真正出现答案,我最终跳过了数据绑定并在动态网格中手动移动控件。

所以,我想我会接受这个作为缺乏更好的答案

Well, no answers have really come up and I ended up skipping the data binding and manually moving controls around in a dynamic grid.

So, I think I'll accept this as the answer in lack of anything better

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