使用RelativeSource绑定到ViewModel不起作用

问题描述 投票:0回答:3

我有一个应用程序,它有一个导航菜单,可以使用命令从一个页面转到另一个页面。

导航菜单已在 Xaml 中创建,我将其存储在 Navigation.xaml 中,请参见下文

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Cirdan.Wpf.Navigation"
xmlns:infrastructure="clr-namespace:Cirdan.Wpf.Infrastructure">

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="/Cirdan.Wpf;component/Resources/Styles/Stylesheet.xaml" />
</ResourceDictionary.MergedDictionaries>

<DataTemplate x:Key="Navigation" >        
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="4*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <UniformGrid Grid.Row="0" Columns="1">
            <Button DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type vm:NavigationViewModelBase}}}" Visibility="{Binding ElementName=Menu, Path=IsChecked, Converter={StaticResource VisibilityConverter}}" Command="{Binding ViewerPageCmd}" >Viewer Screen</Button>
            <Button DataContext="{Binding NavigationViewModel, Source={x:Static infrastructure:MainWindow.LocatorX}}" Visibility="{Binding ElementName=Menu, Path=IsChecked, Converter={StaticResource VisibilityConverter}}" Command="{Binding}" >Acquisition Screen</Button>
            <Button DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type vm:NavigationViewModelBase}}}" Visibility="{Binding ElementName=Menu, Path=IsChecked, Converter={StaticResource VisibilityConverter}}" Command="{Binding WorklistPageCmd}" >Worklist Screen</Button>
        </UniformGrid>
        <ToggleButton Grid.Row="1" Style="{StaticResource ToggleBtnToolStyle}" x:Name="Menu" IsChecked="true" Background="Transparent" BorderThickness="0" >
            <StackPanel Orientation="Horizontal">
                <ContentPresenter Margin="5" Height="50" Content="{StaticResource MenuIcon}"></ContentPresenter>
                <Viewbox>
                    <TextBlock Margin="5" Style="{StaticResource TxtToolStyle}">Menu</TextBlock>
                </Viewbox>
            </StackPanel>
        </ToggleButton>
    </Grid>
</DataTemplate>

我尝试将这些按钮命令绑定到的 ViewModel 称为 NavigationViewModelBase.cs

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;

namespace Cirdan.Wpf.Navigation
{
public abstract class NavigationViewModelBase : ViewModelBase
{
    private List<DicomMetadataModel> _dicomMetadata;

    //Navigation Cmd
    public ICommand AcquisitionPageCmd { get; private set; }
    public ICommand ManualEntryWindowCmd { get; private set; }
    public ICommand SessionWindowCmd { get; private set; }
    public ICommand SettingsWindowCmd { get; private set; }
    public ICommand StudyInfoPageCommandCmd { get; private set; }
    public ICommand ViewerPageCmd { get; private set; }
    public ICommand WorklistPageCmd { get; private set; }


    protected NavigationViewModelBase()
    {
        AcquisitionPageCmd = new RelayCommand(() => Messenger.Default.Send(new GoToPageMessage(Pages.AcquisitionScreen)));
        ManualEntryWindowCmd = new RelayCommand(() => Messenger.Default.Send(new ShowDialogMessage(Pages.ManualEntry, DicomMetadata)));
        SessionWindowCmd = new RelayCommand(() => Messenger.Default.Send(new ShowDialogMessage(Pages.Session)));
        SettingsWindowCmd = new RelayCommand(() => Messenger.Default.Send(new ShowDialogMessage(Pages.Settings)));
        ViewerPageCmd = new RelayCommand(() => Messenger.Default.Send(new GoToPageMessage(Pages.Viewer)));
        WorklistPageCmd = new RelayCommand(() => Messenger.Default.Send(new GoToPageMessage(Pages.Worklist)));
    }
}
}

在每个页面上,我使用以下代码添加导航

<ContentControl Grid.Column="2" Grid.Row="2" ContentTemplate="{StaticResource Navigation }" />

目前我没有收到任何错误,并且当我在上面的按钮之一中设置 DataContext 时,当我去绑定我的命令时,我可以看到该 Viewmodel 的所有属性,以便该位正常工作,但是当我运行程序并单击这些按钮时,没有任何反应。

感谢您的帮助

c# wpf xaml data-binding relativesource
3个回答
3
投票

祖先绑定仅适用于视觉树/视图中的元素或页面中的元素。 viewModel 不在页面中的任何位置作为控件。因此,代替 viewModel 给出具有 NavigationViewModelBase 作为 datacontext.write 绑定的视图类型,如下所示(如果您的视图/控件是 NavigationView,则绑定将是)。并在路径中写入 vm:NavigationViewModelBase 的属性 班级:

<Button DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type v:NavigationView}}, path= PropertyYouWantToBind}"

只要确保您没有为层次结构中的任何其他控件定义 DataContext,按钮将获得与视图相同的 DataContext,然后您只需绑定命令即可。您已经正确完成了。

如果您尚未将 DataContext 提供给视图中的任何控件,则只需将其提供给您的 contentControl 或 Grid。简单地就像

<Grid>
  <Grid.DataContext>
      <vm:NavigationViewModelBase />
  </Grid.DataContext>
<Grid.RowDef.......

然后使用简单的命令绑定。


1
投票

RelativeSource FindAncestor 在 VisualTree 中查找祖先。

VisualTree 看起来像:

Window
   Grid
      TextBlock
      TextBox
      Button

ViewModel 不在视觉三中

例如,在本例中,Button 的祖先是 Grid 和 Window。

那该怎么办呢?

好吧,使用 ResourceDictionary 中的 ContentTemplate 创建自定义

UserControl
代替 ContentControl。

在用户控件中将 DataContext 设置为继承自 NavigationViewModelBase 的类。

那么绑定就简单了:

    <UniformGrid Grid.Row="0" Columns="1">
        <Button Command="{Binding ViewerPageCmd}">Viewer Screen</Button>
        <Button Command="{Binding AcquisitionPageCmd}">Acquisition Screen</Button>
        <Button Command="{Binding WorklistPageCmd}" >Worklist Screen</Button>
    </UniformGrid>

0
投票

如果这在 2024 年对你不起作用,请更新。我这样做了并且有效。

<ItemsWrapGrid x:Name="GridWrap" MaximumRowsOrColumns="4" Orientation="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=DataContext.Toggled, Mode=TwoWay, Converter={StaticResource GridWrapConverter}}"/>
© www.soinside.com 2019 - 2024. All rights reserved.