WPF应用程序中字典的表达式混合和示例数据
我有一个WPF应用程序,我正在使用混合的风格 我的一个视图模型属于以下类型:WPF应用程序中字典的表达式混合和示例数据,wpf,xaml,expression-blend,Wpf,Xaml,Expression Blend,我有一个WPF应用程序,我正在使用混合的风格 我的一个视图模型属于以下类型: public Dictionary<DateTime, ObservableCollection<MyViewModel>> TimesAndEvents 公共字典时间和事件 但是,当我尝试在Expression Blend中创建一些示例数据时,它并没有为此属性创建XAML 可以在XAML中创建这样的数据类型吗?非设计时支持正在扼杀我的生产力。我已经在定位器中创建了我的Viewmodel的设
public Dictionary<DateTime, ObservableCollection<MyViewModel>> TimesAndEvents
公共字典时间和事件
但是,当我尝试在Expression Blend中创建一些示例数据时,它并没有为此属性创建XAML
可以在XAML中创建这样的数据类型吗?非设计时支持正在扼杀我的生产力。我已经在定位器中创建了我的Viewmodel的设计时实例,我引用了上面提到的@ChrisW:
d:DataContext="{Binding Source={StaticResource Locator}, Path=DesignTimeVM}"
所以我可以用一些硬编码的值来填充我的列表、组合框等。这样就可以更容易地设置所有内容的样式
我使用MVVM灯光,因此在ViewModel的构造函数中,我使用如下模式:
if(IsInDesignMode)
{
ListUsers = new List<User>();
.
.
.
}
if(IsInDesignMode)
{
ListUsers=新列表();
.
.
.
}
代码将仅在设计时执行,并且您的Xaml UI将绑定到实际数据。关于最后一个问题:不幸的是,您无法在WPF中轻松实例化词典。我相信这部分解释得很好。这本书很好地总结了链接答案的内容: 此限制的常见解决方法(无法实例化 WPF版本(XAML)中的字典将派生非泛型 从泛型类初始化,以便可以从XAML引用它 但即使如此,在我看来,在xaml中实例化该词典也是一个痛苦的过程。此外,Blend不知道如何创建该类型的示例数据 关于如何获得设计时支持的隐含问题:有几种方法可以在WPF中实现设计时数据,但对于复杂场景,此时我首选的方法是创建自定义数据源提供程序。值得称赞的是:我的想法来自(比这个问题还要古老)
DataSourceProvider解决方案 创建一个实现并返回数据上下文示例的类。将实例化的MainWindowViewModel传递给OnQueryFinished方法是实现这一神奇效果的原因(我建议阅读相关内容以了解其工作原理) MainWindowViewModel.cs MainWindow.xaml 请注意,解决方案中缺少设计数据上下文
<Window x:Class="SampleDataInBlend.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:SampleDataInBlend"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="300">
<Grid>
<ListBox ItemsSource="{Binding TimesAndEvents}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Key}"/>
<ListBox ItemsSource="{Binding Value}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type local:MyViewModel}">
<TextBlock Text="{Binding EventName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
构建并运行
现在,如果一切都正确完成并且充实了MainWindowViewModel的初始化方法(我将在底部包括我的实现),那么在构建和运行WPF应用程序时,您应该会看到如下屏幕:
又是什么问题?
问题是设计视图中没有显示任何内容
我的Initialize()方法
public void Initialize()
{
TimesAndEvents=假装IMAServiceThatGetSDataFormainWindowViewModel();
}
私有IDictionary服务GetSDataFormainWindowViewModel()
{
var myViewModel1=newmyviewmodel{EventName=“I'm real”};
var myViewModel2=newmyviewmodel{EventName=“I'm real”};
var myViewModelCollection1=新的ObservableCollection{myViewModel1,myViewModel2};
var timeToMyViewModelDictionary=新字典
{
{DateTime.Now,myViewModelCollection1}
};
返回timeToMyViewModelDictionary;
}
因为Xaml 2009支持泛型类型,所以可以编写一个松散的Xaml(不能在wpf项目中编译)来表示字典
Data.xaml
<gnrc:Dictionary 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"
xmlns:gnrc="clr-namespace:System.Collections.Generic;assembly=mscorlib"
xmlns:om="clr-namespace:System.Collections.ObjectModel;assembly=System"
x:TypeArguments="sys:DateTime,om:ObservableCollection(x:String)">
<om:ObservableCollection x:TypeArguments="x:String">
<x:Key>
<sys:DateTime>2017/12/31</sys:DateTime>
</x:Key>
<x:String>The last day of the year.</x:String>
<x:String>Party with friends.</x:String>
</om:ObservableCollection>
<om:ObservableCollection x:TypeArguments="x:String">
<x:Key>
<sys:DateTime>2018/1/1</sys:DateTime>
</x:Key>
<x:String>Happy new year.</x:String>
<x:String>Too much booze.</x:String>
</om:ObservableCollection>
<om:ObservableCollection x:TypeArguments="x:String">
<x:Key>
<sys:DateTime>2018/1/10</sys:DateTime>
</x:Key>
<x:String>Just another year.</x:String>
<x:String>Not much difference.</x:String>
</om:ObservableCollection>
</gnrc:Dictionary>
<Window x:Class="WpfApp.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:WpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<ListBox ItemsSource="{local:InstanceFromLooseXaml Source=/Data.xaml}">
<ListBox.ItemTemplate>
<DataTemplate>
<Expander Header="{Binding Key}">
<ListBox ItemsSource="{Binding Value}"/>
</Expander>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>
此标记扩展具有Uri类型的源属性,使用户可以指定要加载的xaml文件。最后,像这样使用标记扩展
main window.xaml
<gnrc:Dictionary 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"
xmlns:gnrc="clr-namespace:System.Collections.Generic;assembly=mscorlib"
xmlns:om="clr-namespace:System.Collections.ObjectModel;assembly=System"
x:TypeArguments="sys:DateTime,om:ObservableCollection(x:String)">
<om:ObservableCollection x:TypeArguments="x:String">
<x:Key>
<sys:DateTime>2017/12/31</sys:DateTime>
</x:Key>
<x:String>The last day of the year.</x:String>
<x:String>Party with friends.</x:String>
</om:ObservableCollection>
<om:ObservableCollection x:TypeArguments="x:String">
<x:Key>
<sys:DateTime>2018/1/1</sys:DateTime>
</x:Key>
<x:String>Happy new year.</x:String>
<x:String>Too much booze.</x:String>
</om:ObservableCollection>
<om:ObservableCollection x:TypeArguments="x:String">
<x:Key>
<sys:DateTime>2018/1/10</sys:DateTime>
</x:Key>
<x:String>Just another year.</x:String>
<x:String>Not much difference.</x:String>
</om:ObservableCollection>
</gnrc:Dictionary>
<Window x:Class="WpfApp.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:WpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<ListBox ItemsSource="{local:InstanceFromLooseXaml Source=/Data.xaml}">
<ListBox.ItemTemplate>
<DataTemplate>
<Expander Header="{Binding Key}">
<ListBox ItemsSource="{Binding Value}"/>
</Expander>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>
在本例中,我将Data.xaml放在应用程序文件夹中,因此“Source=/Data.xaml”就可以了。每次重新加载设计器时(重建将确保它),将应用松散xaml中的内容。结果应该是这样的
松散的xaml可以包含几乎所有内容,如ResourceDictionary或带有UiElements的内容。但是Blend或Visual Studio都不会为您正确检查它。最后,希望这足以作为答案。仍在寻找答案question@Sentry这里可以问很多问题。您是否使用实际的设计时数据提供对模拟视图模型的引用?如果是这样,您能否将设计时数据上下文指定为类似于(在父级上)
d:DataContext=“{StaticResource pathtodesigntimedatavmstuffinesources”的资源类型
所以它只是在设计时将datacontext交换为假的东西?@ChrisW。我在不到一年前开始使用WPF,所以我不太习惯所有的可能性。请原谅我在这里缺乏知识,但我看不出你的问题是什么(模拟视图模型?)与XAML格式的样本数据有关。@Sentry不必担心。至于说你有实际的假数据来提供我假设你在运行时在XAML中的绑定?这些假数据必须存在于某个地方。@ChrisW。我的假数据就是:假。随机字符串,随机数。Blend可以为我的大多数视图模型创建它们,但是n有一个字典,Blend不会生成它。即使对于字典
<Window x:Class="SampleDataInBlend.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:SampleDataInBlend"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="300">
<Grid>
<ListBox ItemsSource="{Binding TimesAndEvents}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Key}"/>
<ListBox ItemsSource="{Binding Value}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type local:MyViewModel}">
<TextBlock Text="{Binding EventName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var viewModel = new MainWindowViewModel();
// MainWindowViewModel needs to have its dictionary filled before its
// bound to as the IDictionary implementation we are using does not do
// change notification. That is why were are calling Initialize before
// passing in the ViewModel.
viewModel.Initialize();
var view = new MainWindow(viewModel);
view.Show();
}
}
public void Initialize()
{
TimesAndEvents = PretendImAServiceThatGetsDataForMainWindowViewModel();
}
private IDictionary<DateTime, ObservableCollection<MyViewModel>> PretendImAServiceThatGetsDataForMainWindowViewModel()
{
var myViewModel1 = new MyViewModel { EventName = "I'm real" };
var myViewModel2 = new MyViewModel { EventName = "I'm real" };
var myViewModelCollection1 = new ObservableCollection<MyViewModel> { myViewModel1, myViewModel2 };
var timeToMyViewModelDictionary = new Dictionary<DateTime, ObservableCollection<MyViewModel>>
{
{ DateTime.Now, myViewModelCollection1 }
};
return timeToMyViewModelDictionary;
}
<gnrc:Dictionary 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"
xmlns:gnrc="clr-namespace:System.Collections.Generic;assembly=mscorlib"
xmlns:om="clr-namespace:System.Collections.ObjectModel;assembly=System"
x:TypeArguments="sys:DateTime,om:ObservableCollection(x:String)">
<om:ObservableCollection x:TypeArguments="x:String">
<x:Key>
<sys:DateTime>2017/12/31</sys:DateTime>
</x:Key>
<x:String>The last day of the year.</x:String>
<x:String>Party with friends.</x:String>
</om:ObservableCollection>
<om:ObservableCollection x:TypeArguments="x:String">
<x:Key>
<sys:DateTime>2018/1/1</sys:DateTime>
</x:Key>
<x:String>Happy new year.</x:String>
<x:String>Too much booze.</x:String>
</om:ObservableCollection>
<om:ObservableCollection x:TypeArguments="x:String">
<x:Key>
<sys:DateTime>2018/1/10</sys:DateTime>
</x:Key>
<x:String>Just another year.</x:String>
<x:String>Not much difference.</x:String>
</om:ObservableCollection>
</gnrc:Dictionary>
public class InstanceFromLooseXamlExtension : MarkupExtension
{
public Uri Source { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (Source == null)
{
throw new ArgumentNullException(nameof(Source));
}
Uri source;
if (Source.IsAbsoluteUri)
{
source = Source;
}
else
{
var iuc = serviceProvider?.GetService(typeof(IUriContext)) as IUriContext;
if (iuc == null)
{
throw new ArgumentException("Bad service contexts.", nameof(serviceProvider));
}
source = new Uri(iuc.BaseUri, Source);
}
WebResponse response;
if (source.IsFile)
{
response = WebRequest.Create(source.GetLeftPart(UriPartial.Path)).GetResponse();
}
else if(string.Compare(source.Scheme, PackUriHelper.UriSchemePack, StringComparison.Ordinal) == 0)
{
var iwrc = new PackWebRequestFactory() as IWebRequestCreate;
response = iwrc.Create(source).GetResponse();
}
else
{
throw new ArgumentException("Unsupported Source.", nameof(Source));
}
object result;
try
{
result = XamlReader.Load(response.GetResponseStream());
}
finally
{
response.Close();
}
return result;
}
}
<Window x:Class="WpfApp.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:WpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<ListBox ItemsSource="{local:InstanceFromLooseXaml Source=/Data.xaml}">
<ListBox.ItemTemplate>
<DataTemplate>
<Expander Header="{Binding Key}">
<ListBox ItemsSource="{Binding Value}"/>
</Expander>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>