【问题标题】:Binding to design data in WPF绑定到 WPF 中的设计数据
【发布时间】:2016-12-17 13:16:32
【问题描述】:

我有一个包含 ListBox 的 WPF 窗口。 ItemsSource 绑定到视图模型的属性。

<Window x:Class="SimpleWpfApp.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{Binding MainWindowViewModel, Source={StaticResource Locator}}">
  <DockPanel>
    <ListBox ItemsSource="{Binding SomeThings}" />
  </DockPanel>
</Window>

视图模型的属性是自定义接口的可观察集合; ISome 接口。接口非常简单,由 SomeClass 实现,另外重写了 ToString。

public class MainWindowViewModel
{
  public ObservableCollection<ISomeInterface> SomeThings
  {
    get
    {
      var list = new List<ISomeInterface>
      {
        new SomeClass {Value = "initialised"},
        new SomeClass {Value = "in"},
        new SomeClass {Value = "code"}
      };

      return new ObservableCollection<ISomeInterface>(list);
    }
  }
}

public interface ISomeInterface
{
  string Value { get; }
}

public class SomeClass : ISomeInterface
{
  public string Value { get; set; }

  public override string ToString() => Value;
}

当我在 Visual Studio 2015 或 Blend 中查看窗口时,一切都符合预期。调用 ToString 并填充 ListBox。

Blend screenshot

我已经创建了我想在设计模式下使用的 XAML 设计数据。我已将设计数据添加到名为 SampleData 的目录中。我在第一个 DataContext 正下方的窗口 XAML 中添加了一个设计 datacontext 语句。

d:DataContext="{d:DesignData Source=/SampleData/Data.xaml}"

这不起作用。无论我将什么用于源路径,Visual Studio 和 Blend 都会报告“找不到文件或项目项”。我试过 /SampleData/Data.xaml、SampleData/Data.xaml、../SampleData/Data.xaml、./../SampleData/Data.xaml

Visual Studio 和 Blend 只有在我将 Data.xaml 移出 SampleData 目录并移到项目根目录时才能找到它。然后我可以使用源路径 /Data.xaml 或 Data.xaml 来引用它。如果我使用 Data.xaml 而不使用 / 前缀,那么 Visual Studio 和 Blend 会报告找不到该文件.. 但无论如何都能找到它。

我的第一个问题是.. 我可以在子目录中使用示例数据吗?如果是的话怎么办?

在项目根目录中成功引用 Data.xaml 后,我的窗口没有调用被覆盖的 ToString,因此我得到了一个显示的类名列表。该列表与设计数据具有相同数量的项目,因此看起来它正在使用设计数据。

我的第二个问题是.. 如果对象是从代码中实例化的,为什么这里不调用被覆盖的 ToString?

我知道我可以通过指定一个项目模板来实现所需的结果。

<ListBox ItemsSource="{Binding SomeThings}">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding Value}"/>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

github 上的示例应用程序的完整源代码可供使用

https://github.com/DangerousDarlow/WpfDesignData

更新

感谢 jstreet 的回答。我更改了子目录中 data.xaml 的文件属性,现在可以将其用作设计数据。我以为我以前试过这个,但我一定是弄错了。

我仍然没有看到 ToString 被调用。我尝试将视图模型属性更改为 List&lt;object&gt;List&lt;ISomeInterface&gt; 但都导致调用 object.ToString;由类名的显示推断。我可能会停止关注这一点,因为无论如何我都不会使用 ToString,我将绑定到我想要显示的属性。不过,最好解释一下行为上的差异。

我使用的是 Visual Studio 2015 社区版。

【问题讨论】:

    标签: c# wpf xaml visual-studio-2015 design-data


    【解决方案1】:

    这里有一些工作示例代码。您可能想参考This article - MSDN

    特别要注意如何在 VS 项目中为 Data.xaml 文件(在我的例子中为 Dictionary1.xaml)设置属性:

    还要注意如何创建你的根对象SomeThings(在我的例子中是SomeClasses):

    对于集合,根对象可以是 ArrayList 或派生自集合或泛型集合的自定义类型...

    XAML:

    <Window x:Class="WpfApplication277.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication277"
        d:DataContext="{d:DesignData Source=/SampleData/Dictionary1.xaml}"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <ListView ItemsSource="{Binding}"></ListView>
    </Grid>
    

    Dictionary1.xaml:

    右键单击 VS 项目中的 SampleData 文件夹,然后选择 Add\New Item\WPF\Resource Dictionary,将其内容替换为您的设计数据。这应该确保您的设计数据可以位于子文件夹中。

    <m:SomeClasses xmlns:m="clr-namespace:WpfApplication277">
    <m:SomeClass Value="design data 1">
    </m:SomeClass>
    <m:SomeClass Value="design data 2">
    </m:SomeClass>
    <m:SomeClass Value="design data 3">
    </m:SomeClass>
    

    SomeClasses: List&lt;SomeClass&gt; 没有工作!

    public class SomeClasses : List<Object>
    {
        public SomeClasses() { }
    }
    

    SomeClass:

    public class SomeClass : ISomeInterface
    {
        public string Value { get; set; }
    
        public override string ToString() => string.Format("ToString() : {0}",Value);
    }
    

    请注意,ToString() 肯定会被调用:

    【讨论】:

    • 感谢您的回答。我有一些后续问题,但它们太罗嗦了,无法发表评论。发布它们的最佳方式是什么?
    • 您可以编辑原始问题的底部并添加后续问题。
    猜你喜欢
    • 2011-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-20
    • 1970-01-01
    相关资源
    最近更新 更多