gpt4 book ai didi

windows-phone-7 - 全景 wp7 mvvm 中的静态和动态全景项目

转载 作者:行者123 更新时间:2023-12-03 10:24:23 26 4
gpt4 key购买 nike

这是我的情况。

ViewModelA {  
ObservableCollection<Items> ItemsA
ObservableCollection<ViewModelB> ViewModelBs
}

将数据上下文设置为 ViewModel A 的 View A
ViewA 有一个包含列表框、面板、文本 block 等的全景图,列表框的项目源绑定(bind)到 ItemsA

我想在运行时使用通用数据模板(列表框、文本 block ...等)将其他全景项目添加到全景控件。每个全景项目将在运行时绑定(bind)到 ViewModelBs 集合中的每个 ViewModelB。

我不反对为此做一些代码隐藏的东西,因为我不是一个严格的 mvvm 纯粹主义者..
但如果我可以指定控制和数据模板并使其工作,该解决方案可能会很优雅。我对 wpf/xaml 有点陌生,并试图通过编写 wp7 应用程序来闯入这些技术。使用 mvvm light 框架。最终,我希望我的动态生成的全景项目/列表框内容触发中继命令他们被绑定(bind)到的 View 模型......

这是我尝试工作失败的一些代码片段。希望它提供一些想法..
<phone:PhoneApplicationPage.Resources>
<Style x:Key="PanoramaItemStyle" TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Grid x:Name="ContentGrid">
<controls:PanoramaItem x:Name="ItemLocationPanoramaItem" Header="{Binding TagName}">
<StackPanel >
<ListBox x:Name="ItemLocatorsList" ItemsSource="{Binding ItemLocators}" Height="496" SelectedItem="{Binding SelectedItemLocation, Mode=TwoWay}" >
<Custom:Interaction.Triggers>
<Custom:EventTrigger EventName="SelectionChanged">
<GalaSoft_MvvmLight_Command:EventToCommand x:Name="SelectionChangedEvent" Command="{Binding RelativeSource={RelativeSource TemplatedParent},Path=DataContext.GoToEditItemLocatorCommand}" PassEventArgsToCommand="True"/>
</Custom:EventTrigger>
</Custom:Interaction.Triggers>
<ListBox.ItemsPanel>
<ItemsPanelTemplate >
<StackPanel Orientation="Vertical" ScrollViewer.VerticalScrollBarVisibility="Auto" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,17">
<StackPanel Width="311">
<TextBlock Text="{Binding Path=Item.Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextLargeStyle}"/>
<TextBlock Text="{Binding Path=Location.Description}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</controls:PanoramaItem>
<ContentPresenter/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="White"/>
</Style>
</phone:PhoneApplicationPage.Resources>

































代码隐藏:
私有(private) LocationGroupsViewModel viewModel = null;
    public LocationGroups()
{
InitializeComponent();
LocationGroupsPanaroma.DefaultItem = LocationGroupsPanaroma.Items[0];
viewModel = this.DataContext as LocationGroupsViewModel;
CreateDynamicPanaromaItems();
}


private void CreateDynamicPanaromaItems()
{
foreach (Model.LocationGroup group in viewModel.LocationGroups)
{
if (group.TotalItems > 0)
{
PanoramaItem pi = new PanoramaItem();
pi.Header = group.Name;
pi.Orientation = System.Windows.Controls.Orientation.Horizontal;
ItemLocationListViewModel itemLocationViewModel = viewModel[group.LocationGroupId];
pi.DataContext = itemLocationViewModel;
pi.Style = Resources["PanoramaItemStyle"] as Style;
LocationGroupsPanaroma.Items.Add(pi);

}
}

}

编辑

ViewModel A 有
Items collection

Collection of ViewModelBs

panaroma 数据上下文设置为 viewmodelA
panaroma item - Statitically created in xaml to some Items collection in ViewModelA

This pan item has a list box



panaroma items --- to be bound to collection of viewmodelbs

These pan items should each have a listbox which is selectable
and bound to some collection in View Model B and fires commands on selection changed to viewModelB. Currently using the galasoft eventtocommand to hook the selection changed on the
list box to a relay command. The problem is that this eventtommand should have the viewmodel as its data context and the not the collection (bound to the listbox) within viewmodel.

最佳答案

好的,终于有时间回答问题了。提议的解决方案不需要任何代码,仅依赖于 MVVM 概念和数据绑定(bind)。

从概念上讲 Panorama control 是一个 ItemPresenter (它继承自 ItemsPresenter ),即您可以绑定(bind) ItemsSource到包含代表您的 PanoramaItems 的项目的列表.

渲染您的 PanoramaItem您必须为 Panorama.HeaderTemplate 提供模板和 Panorama.ItemTemplate . DataContext模板里面是ViewModel代表您的PanoramaItem .如果这个 ViewModel包含一个项目列表,您现在可以使用它来生成 ListBoxes你在找。

这是示例...

ViewModelLocator.cs

using GalaSoft.MvvmLight;

namespace WP7Test.ViewModel
{
public class ViewModelLocator
{
private static MainViewModel _main;

public ViewModelLocator()
{
if (ViewModelBase.IsInDesignModeStatic) {
// Create design time services and viewmodels
} else {
// Create run time services and view models
}
_main = new MainViewModel();
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public MainViewModel Main
{
get
{
return _main;
}
}
}
}

MainViewModel.cs
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
this.Items = new ObservableCollection<ItemViewModel>();

if (IsInDesignMode) {
// Code runs in Blend --> create design time data.
} else {
// Code runs "for real"
}
this.LoadData();
}

#region [Items]

public const string ItemsPropertyName = "Items";

private ObservableCollection<ItemViewModel> _items = default(ObservableCollection<ItemViewModel>);

public ObservableCollection<ItemViewModel> Items {
get {
return _items;
}
private set {
if (_items == value) {
return;
}

var oldValue = _items;
_items = value;

RaisePropertyChanged(ItemsPropertyName);
}
}

#endregion

private void LoadData() {
this.Items.Add(new ItemViewModel() { LineOne = "runtime one", LineTwo = "Maecenas praesent accumsan bibendum", LineThree = "Facilisi faucibus habitant inceptos interdum lobortis nascetur pharetra placerat pulvinar sagittis senectus sociosqu" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime two", LineTwo = "Dictumst eleifend facilisi faucibus", LineThree = "Suscipit torquent ultrices vehicula volutpat maecenas praesent accumsan bibendum dictumst eleifend facilisi faucibus" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime three", LineTwo = "Habitant inceptos interdum lobortis", LineThree = "Habitant inceptos interdum lobortis nascetur pharetra placerat pulvinar sagittis senectus sociosqu suscipit torquent" });

foreach (var item in Items) {
for (int i = 0; i < 5; ++i)
item.Items.Add(new ItemViewModel() { LineOne = "Item " + i, LineTwo = "Maecenas praesent accumsan bibendum" });
}
}
}

ItemViewModel.cs
public class ItemViewModel : ViewModelBase
{
public ItemViewModel() {
this.Items = new ObservableCollection<ItemViewModel>();

if (IsInDesignMode) {
// Code runs in Blend --> create design time data.
} else {
// Code runs "for real": Connect to service, etc...
}
}

public override void Cleanup() {
// Clean own resources if needed

base.Cleanup();
}

#region [LineOne]

public const string LineOnePropertyName = "LineOne";

private string _lineOne = default(string);

public string LineOne {
get {
return _lineOne;
}

set {
if (_lineOne == value) {
return;
}

var oldValue = _lineOne;
_lineOne = value;
RaisePropertyChanged(LineOnePropertyName);
}
}

#endregion

#region [LineTwo]

public const string LineTwoPropertyName = "LineTwo";

private string _lineTwo = default(string);

public string LineTwo {
get {
return _lineTwo;
}

set {
if (_lineTwo == value) {
return;
}

var oldValue = _lineTwo;
_lineTwo = value;

RaisePropertyChanged(LineTwoPropertyName);
}
}

#endregion

#region [LineThree]

public const string LineThreePropertyName = "LineThree";

private string _lineThree = default(string);

public string LineThree {
get {
return _lineThree;
}

set {
if (_lineThree == value) {
return;
}

var oldValue = _lineThree;
_lineThree = value;
RaisePropertyChanged(LineThreePropertyName);
}
}

#endregion

#region [Items]

public const string ItemsPropertyName = "Items";

private ObservableCollection<ItemViewModel> _items = default(ObservableCollection<ItemViewModel>);

public ObservableCollection<ItemViewModel> Items {
get {
return _items;
}
private set {
if (_items == value) {
return;
}

var oldValue = _items;
_items = value;
RaisePropertyChanged(ItemsPropertyName);
}
}

#endregion
}

MainPage.xaml
<phone:PhoneApplicationPage 
x:Class="WP7Test.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="False">

<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent" DataContext="{Binding Main, Source={StaticResource Locator}}">
<controls:Panorama Title="my application" ItemsSource="{Binding Items}">
<controls:Panorama.Background>
<ImageBrush ImageSource="PanoramaBackground.png"/>
</controls:Panorama.Background>
<controls:Panorama.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding LineOne}"/>
</DataTemplate>
</controls:Panorama.HeaderTemplate>
<controls:Panorama.ItemTemplate>
<DataTemplate>
<StackPanel>
<Border BorderThickness="0,0,0,1" BorderBrush="White">
<TextBlock Text="{Binding LineTwo}" FontSize="28" TextWrapping="Wrap"/>
</Border>
<Border BorderThickness="0,0,0,1" Margin="0,20" BorderBrush="White">
<TextBlock Text="{Binding LineThree}" TextWrapping="Wrap"/>
</Border>
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding LineOne}" FontSize="24"/>
<TextBlock Text="{Binding LineTwo}" FontSize="18" Margin="24,0,0,5"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</controls:Panorama.ItemTemplate>
</controls:Panorama>
</Grid>
<!--Panorama-based applications should not show an ApplicationBar-->
</phone:PhoneApplicationPage>

编辑 - 添加额外的第一个面板

终于明白你想要达到的目的了!但是,您仍然不需要后面的代码来做到这一点!您只需要一个模板...对于此 Blend 确实可以帮助您,因为它可以让您为现有控件提取模板...好的,这是更改。

首先,我向 MainViewModel 添加了一个新属性以显示一些数据:
#region [MainPageProperty]

public const string MainPagePropertyPropertyName = "MainPageProperty";
private string _mainPageProperty = "Facilisi faucibus habitant inceptos interdum lobortis nascetur pharetra placerat pulvinar sagittis senectus sociosqu";

public string MainPageProperty {
get {
return _mainPageProperty;
}
set {
if (_mainPageProperty == value) {
return;
}

_mainPageProperty = value;
RaisePropertyChanged(MainPagePropertyPropertyName);
}
}

#endregion

然后我使用 Blend 来获取 Panorama 控件的模板并将其插入到 controls:Panorama元素。
<controls:Panorama.Template>
<ControlTemplate TargetType="controls:Panorama">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<controlsPrimitives:PanningBackgroundLayer x:Name="BackgroundLayer" HorizontalAlignment="Left" Grid.RowSpan="2">
<Border x:Name="background" Background="{TemplateBinding Background}" CacheMode="BitmapCache"/>
</controlsPrimitives:PanningBackgroundLayer>
<controlsPrimitives:PanningTitleLayer x:Name="TitleLayer" CacheMode="BitmapCache" ContentTemplate="{TemplateBinding TitleTemplate}" Content="{TemplateBinding Title}" FontSize="187" FontFamily="{StaticResource PhoneFontFamilyLight}" HorizontalAlignment="Left" Margin="10,-76,0,9" Grid.Row="0"/>
<controlsPrimitives:PanningLayer x:Name="ItemsLayer" HorizontalAlignment="Left" Grid.Row="1">
<StackPanel Orientation="Horizontal">
<controls:PanoramaItem Header="Main panel" Width="432">
<TextBlock Text="{Binding ElementName=LayoutRoot, Path=DataContext.MainPageProperty}" TextWrapping="Wrap"/>
</controls:PanoramaItem>
<ItemsPresenter x:Name="items"/>
</StackPanel>
</controlsPrimitives:PanningLayer>
</Grid>
</ControlTemplate>
</controls:Panorama.Template>

这里有两个技巧,首先我插入了一个 StacPanel 以允许 controlPrimitives:PanningLayer 下面的多个元素名称为 ItemsPanel .进入这个 StackPanel我移动了 ItemsPresenter并添加了另一个 PanoramaItem .不过,重要的一件事是设置 Width PanoramaItem 的属性(property),否则面板将延伸到所需的房间。

另一个技巧是为了访问 DataContext我不得不使用 ElementName在绑定(bind)中。

希望这显示了 MVVM 和模板的力量!

关于windows-phone-7 - 全景 wp7 mvvm 中的静态和动态全景项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6500650/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com