C# UWP数据绑定:如何将button命令设置为DataTemplate内的父DataContext
简短的需求说明:我需要使用ViewModel的DataContext中的一个方法,在DataTemplate中启动一个按钮的命令 问题的简短解释:模板化按钮命令似乎只能绑定到项本身的datacontext。WPF和Windows 8.1应用程序在可视化树中使用的语法似乎不起作用,包括ElementName和祖先绑定。我非常不希望按钮命令位于模型内部 旁注:这是使用MVVM设计方法构建的 下面的代码生成视图上的项目列表。该列表是每个列表项的一个按钮C# UWP数据绑定:如何将button命令设置为DataTemplate内的父DataContext,c#,xaml,data-binding,uwp,datacontext,C#,Xaml,Data Binding,Uwp,Datacontext,简短的需求说明:我需要使用ViewModel的DataContext中的一个方法,在DataTemplate中启动一个按钮的命令 问题的简短解释:模板化按钮命令似乎只能绑定到项本身的datacontext。WPF和Windows 8.1应用程序在可视化树中使用的语法似乎不起作用,包括ElementName和祖先绑定。我非常不希望按钮命令位于模型内部 旁注:这是使用MVVM设计方法构建的 下面的代码生成视图上的项目列表。该列表是每个列表项的一个按钮 <ItemsCon
<ItemsControl x:Name="listView" Tag="listOfStories" Grid.Row="0" Grid.Column="1"
ItemsSource="{x:Bind ViewModel.ListOfStories}"
ItemTemplate="{StaticResource storyTemplate}"
Background="Transparent"
IsRightTapEnabled="False"
IsHoldingEnabled="False"
IsDoubleTapEnabled="False"
/>
在许多其他尝试中,我试着通过ElementName设置它,但都失败了。Intellisense在输入ElementName时将“storyTemplate”检测为选项,ElementName是此问题的第一个代码块中显示的DataTemplate的名称
我不相信我的问题是独一无二的,但是我很难找到UWP的解决方案。请允许我提前道歉,这是一个简单的问题,但我已经花了近两天的时间研究答案,似乎没有一个答案适用于UWP
谢谢你们 有几种方法可以做到这一点。但我认为命令改变得更好 例如,您有一个(网格、列表)视图,其中包含一些itemtemplate,如下所示:
<GridView.ItemTemplate>
<DataTemplate>
<Grid
x:Name="gdVehicleImage"
Height="140"
Width="140"
Background="Gray"
Margin="2"
>
</Grid>
</GridView.ItemTemplate>
不完全是美丽的。。。但您不会像这样破坏mvvm模式…不幸的是,UWP中没有祖先绑定。这使得像您这样的场景更难实现 我能想到的唯一方法是在
页面上为ViewModel
创建一个dependencProperty
:
public ChooseStoryToPlay_ViewModel ViewModel
{
get { return (ChooseStoryToPlay_ViewModel)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(ChooseStoryToPlay_ViewModel), typeof(MainPage), new PropertyMetadata(0));
现在,您可以从数据模板绑定到它:
<DataTemplate x:Name="storyTemplate" x:DataType="local:Story">
<Button
Margin="0,6,0,0"
Width="{Binding ColumnDefinitions[1].ActualWidth, ElementName=storyGrid, Mode=OneWay}"
HorizontalContentAlignment="Stretch"
CommandParameter="{x:Bind Page}"
Command="{Binding ViewModel.NavigateCommand, ElementName=Page}">
<StackPanel HorizontalAlignment="Stretch" >
<TextBlock Text="{x:Bind StoryTitle, Mode=OneWay}"
FontSize="30"
TextTrimming="WordEllipsis"
TextAlignment="Left"/>
</StackPanel>
</Button>
</DataTemplate>
我希望这有助于并适用于您的场景。您正在使用什么MVVM工具包(如果有的话)?在MVVM Light中,您可以从DataTemplate获得ViewModel,方法与为视图设置DataContext相同:
<DataTemplate x:Key="SomeTemplate">
<Button Command="{Binding Main.MyCommand, Source={StaticResource ViewModelLocator}}"/>
</DataTemplate>
我从未尝试过UWP,但在其他基于XAML的框架中,通常使用UWP进行处理。如果没有帮助的话,那可能是因为数据模板在参考资料中(尽管这是可疑的),或者UWP XAML有自己的一些特殊性。是的,先生,这就是导致我如此沮丧的原因。我做的第一件事是RelativeSource祖先绑定,就像我在过去的平台上做的一样,但这次它不起作用。谢谢。我真的很感谢你花时间通读我的问题,并把代码放在一起。不过,恐怕这对我的申请没有多大帮助。我只需要启动button命令即可激活viewmodel上的backing命令,该命令将导航到另一个页面,同时携带任何参数。不过,再次感谢你!是的,只要想想你喜欢的按钮弹出菜单。。。将您的按钮命令放入已加载的事件中,但保留带有绑定的CommandParameter。。。您将使用带有参数的命令导航到另一个页面:数据这太棒了。非常感谢您解决了祖先绑定是否可用的问题。我几乎已经决定,在无法绑定到视图模型命令的情况下,有两个选项可用。在模型上创建一个命令,并将故事作为一个参数传入,这是我不愿意做的…或者在视图后端的按钮上应用一个click参数。这是一个小小的咆哮,但我觉得难以理解的是,微软吹嘘为程序未来的平台剥夺了这一功能。再次感谢你,达米尔!如果DataContext位于ResourceDictionary中,则这没有帮助。有人找到了合适的解决方案吗?这会实例化新的、断开连接的ViewModel版本吗?谢谢你的回答!不,不会的。在ViewModelLocator Main中,应该只从默认ServiceLocator获取MainViewModel的实例,该默认ServiceLocator返回singleton。拍额头我现在觉得自己像个十足的白痴。西恩,请允许我最真诚地感谢你。看着这段代码,我的眼睛有些模糊,但我认为你的代码可以工作!确保定位器中的所有内容都正确无误,它将像一个符咒一样工作。很高兴能帮忙。顺便说一句,爱你的头像。我是谢泼德指挥官,我同意你的回答。
private void mfiDeletePic_Loaded(object sender, RoutedEventArgs e)
{
var m = (MenuFlyoutItem)sender;
if (m != null)
{
m.Command = Vm.DeleteImageCommand;
//Vm is the ViewModel instance...
}
}
public ChooseStoryToPlay_ViewModel ViewModel
{
get { return (ChooseStoryToPlay_ViewModel)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(ChooseStoryToPlay_ViewModel), typeof(MainPage), new PropertyMetadata(0));
<DataTemplate x:Name="storyTemplate" x:DataType="local:Story">
<Button
Margin="0,6,0,0"
Width="{Binding ColumnDefinitions[1].ActualWidth, ElementName=storyGrid, Mode=OneWay}"
HorizontalContentAlignment="Stretch"
CommandParameter="{x:Bind Page}"
Command="{Binding ViewModel.NavigateCommand, ElementName=Page}">
<StackPanel HorizontalAlignment="Stretch" >
<TextBlock Text="{x:Bind StoryTitle, Mode=OneWay}"
FontSize="30"
TextTrimming="WordEllipsis"
TextAlignment="Left"/>
</StackPanel>
</Button>
</DataTemplate>
public ICommand NavigateCommand { get; } =
new RelayCommand<string>(name => Debug.WriteLine(name));
<DataTemplate x:Key="SomeTemplate">
<Button Command="{Binding Main.MyCommand, Source={StaticResource ViewModelLocator}}"/>
</DataTemplate>