【问题标题】:Defining data source declaratively in XAML在 XAML 中以声明方式定义数据源
【发布时间】:2014-06-27 16:00:42
【问题描述】:

我有带有小型静态数据源的列表控件。例如:

<ItemsControl ItemsSource="{Binding Countries}" .../>

我的视图模型填充列表:

this.Countries.Add(new Country { Code = "BE", Name = "Belgium" });
this.Countries.Add(new Country { Code = "CA", Name = "Canada" });
// etc.

是否有替代方法可以在 XAML 中定义列表内容?比如:

<ItemsControl>
    <ItemsControl.ItemsSource>
        <somenamespace:list>
            <mynamespace:Country Code="BE" Name="Belgium" />
            etc.
        </somenamespace:list>
    </ItemsControl.ItemsSource>
</ItemsControl>

我实际上会将列表放在单独的资源文件中,并希望在将它们定义为资源后执行ItemsSource="{StaticResource myListOfCountries}"

我想这样做是为了减轻我的 VM 中的样板代码。我想知道它是否会对性能产生负面影响,因为可以在渲染视图之前创建这些对象,而我可以稍后加载这些对象(导航到,视图加载,... vs 构造函数)。欢迎任何想法!

【问题讨论】:

  • 此链接here 可能会对您有所帮助。

标签: c# wpf xaml windows-phone-8


【解决方案1】:

您可以通过创建一个新的 CollectionType,然后在 XAML 中填充它来做到这一点。

例子,

将在 XAML 中使用的集合类型:

using System.Collections.ObjectModel;

namespace WpfApplication4
{
    public class CountryCollection : ObservableCollection<Country>
    {
    }
}

POCO:

using System;
using System.Collections;

namespace WpfApplication4
{
    public class Country 
    {
        public String Name { get; set; }
        public String Code { get; set; }
    }
}

XAML:

<Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication4"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:CountryCollection x:Key="CountryList">
            <local:Country Name="Canada" Code="CA"/>
            <local:Country Name="United States" Code="US"/>
            <local:Country Name="Belgium" Code="BE"/>
        </local:CountryCollection>
    </Window.Resources>
    <Grid>
        <ItemsControl ItemsSource="{StaticResource CountryList}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Label Content="{Binding Name}"/>
                        <Label Content="{Binding Code}"/>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>

注意,提供的 XAML 类似于:

    var CountryList = new ObservableCollection<Country>
    {
        new Country {Name = "Canada", Code = "CA"},
        new Country {Name = "United States", Code = "US"},
        new Country {Name = "Belgium", Code = "BE"}
    };

编辑(使用 ArrayList 更新)

通过 XAML 中定义的 Collections 命名空间,您可以使用

   xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"

<Window.Resources>
    <collections:ArrayList x:Key="CountryList">
        <local:Country Name="Canada" Code="CA"/>
        <local:Country Name="United States" Code="US"/>
        <local:Country Name="Belgium" Code="BE"/>
    </collections:ArrayList>
</Window.Resources>

【讨论】:

  • 你不需要在公共类 CountryCollection 上设置吗?
  • @Blam 不,CountryCollection 派生自 ObservableCollection,因此不需要创建 setter/getter。通过继承,它仍将具有 ObservableCollection 的所有正常功能。查看我的编辑
  • 谢谢,我会试试这个。有没有办法不必创建新的集合类型?在这种情况下,我什至不需要 ObservableCollection,List 会做(例如)。想知道我是否可以重用现有的泛型类型。
  • @mleroy 是的,如果您不打算使用 ObservableCollection,则不必创建新类型。您可以简单地使用 ArrayList 代替(我在更新中添加了 XAML)
【解决方案2】:

这就是纯 XAML 的方法:

<Window x:Class="WpfApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow"
        Height="350"
        Width="525">
    <Window.Resources>
        <XmlDataProvider x:Key="MockList"
                         XPath="/MockObjects/*">
            <x:XData>
                <MockObjects xmlns="">
                    <MockObject  Code="BE"
                                 Name="Belgium" />
                    <MockObject  Code="CA"
                                 Name="Canada" />
                    <MockObject  Code="US"
                                 Name="USA! USA!" />
                </MockObjects>
            </x:XData>
        </XmlDataProvider>
    </Window.Resources>
    <Grid DataContext="{Binding Source={StaticResource MockList}}">
        <ItemsControl ItemsSource="{Binding Mode=Default, XPath=/MockObjects/MockObject}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding XPath=@Code}" FontWeight="Bold" Margin="0 0 5 0"/>
                        <TextBlock Text="{Binding XPath=@Name}" />
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>

我使用this SO answer 作为参考。

【讨论】:

  • 意识到这种方法会破坏 MVVM,因为您的“模型”(Country)仅在您的视图数据中提供。或者,您可以编写一个 XML 文件并在 ViewModel 初始化期间将其解析为对象。
猜你喜欢
  • 1970-01-01
  • 2023-03-16
  • 2018-12-02
  • 2012-01-15
  • 2017-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-19
相关资源
最近更新 更多