属性 与多个用户控件级别的 WPF 绑定

WPF binding of property with multiple usercontrols level

我有两个用户控件(LoginView.xaml 和 DashboardView.xaml)。 DashboardView.xaml 放在里面 LoginView.xaml 。 现在,我的 objective 最初 DashboardView 应该是不可见的,登录成功后它应该是可见的,stackpanel "loginSP" 中的控件应该是不可见的。

LoginView.xaml如下:-

<UserControl x:Class="DashboardModule.LoginView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:DashboardModule"
         xmlns:converter="clr-namespace:Matrix.Infrastructure.Framework.Utility;assembly=Matrix.Infrastructure"
         mc:Ignorable="d" 
         x:Name="loginUC"
         d:DesignHeight="450" d:DesignWidth="800"  Background="Pink">
<UserControl.Resources>
    <ResourceDictionary>
        <converter:BooleanToVisibilityConverter x:Key="BoolVisibilityConverter"></converter:BooleanToVisibilityConverter>
    </ResourceDictionary>
</UserControl.Resources>
<StackPanel Margin="200">
    <StackPanel x:Name="loginSP">
        <TextBlock Text="Dashboard" ></TextBlock>
        <TextBox x:Name="tbUserName" Height="25" Width="300" ></TextBox>
        <PasswordBox Margin="2"></PasswordBox>
        <Button Content="Login" Command="{Binding LoginCommand}" CommandParameter="{Binding Path=Text,ElementName=tbUserName}"  Width="200"
            ></Button>
    </StackPanel>       

    <ContentControl>
        <ContentControl.Template>
            <ControlTemplate TargetType="{x:Type ContentControl}">
                <Grid>
                    <Border >
                        <ContentPresenter/>
                    </Border>
                </Grid>
            </ControlTemplate>
        </ContentControl.Template>
        <local:DashboardView  Visibility="{Binding DashboardVisible, Converter={StaticResource BoolVisibilityConverter}}"/>
    </ContentControl>       

</StackPanel>

DashboardView.xaml如下:-

<UserControl x:Class="DashboardModule.DashboardView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:DashboardModule"
         xmlns:converter="clr-namespace:Matrix.Infrastructure.Framework.Utility;assembly=Matrix.Infrastructure"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800" Background="BlanchedAlmond" x:Name="DashboardUC"
         Visibility="{Binding Visibility,ElementName=rootGrd}">
<UserControl.Resources>
    <ResourceDictionary>
        <converter:BooleanToVisibilityConverter x:Key="BoolVisibilityConverter"></converter:BooleanToVisibilityConverter>
    </ResourceDictionary>
</UserControl.Resources>
<Grid  x:Name="rootGrd" ToolTip="{Binding MyName, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
       Visibility="{Binding DashboardVisible,Converter={StaticResource BoolVisibilityConverter}}">
    <TextBlock Text="{Binding MyName, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"></TextBlock>          
</Grid>

我的LoginViewModel.cs如下:--

private readonly IEventAggregator eventAggregator;
    public DelegateCommand<string> LoginCommand { get; set; }           
    public DashboardViewModel DashborardVM { get; set; }
    public LoginViewModel(IEventAggregator eventAggregator)
    {
        this.eventAggregator = eventAggregator;
        DashborardVM = new DashboardViewModel();
        LoginCommand = new DelegateCommand<string>(Login, IsValid);
    }

    private void Login(string obj)
    {
        DashborardVM.MyName = "My Name After Login";
        DashborardVM.DashboardVisible = true;
        //this.eventAggregator.GetEvent<ShellLayoutChangeEvent>().Publish("anindya");
    }

    private bool IsValid(string param)
    {
        if (param.Length > 0)

我的 DashboardViewModel.cs 代码如下:-

private bool _dashboardVisible;
    public bool DashboardVisible
    {
        get
        {
            return _dashboardVisible;
        }
        set
        {
            _dashboardVisible = value;
            OnPropertyChanged("DashboardVisible");
        }

    }
    private string myName;
    public string MyName
    {
        get
        {
            return myName;
        }
        set
        {
            myName = value;
            OnPropertyChanged("MyName");
        }
    }

    public DashboardViewModel()
    {
        MyName = "anindya";            
    }

现在输出是: 1.Initially DashboardView 不可见。 2. 登录成功时,尽管我设置 DashborardVM.DashboardVisible = true,但 DashboardView 不可见;在我的 loginviewmode.cs.

我正在使用 Prism 设计模式。 我通过以下方式注册视图和视图模型。

public class ModuleDashboardModule: IModule
{
    IUnityContainer _container;
    IRegionManager _regionManager;

    public ModuleDashboardModule(IUnityContainer container,
                                IRegionManager regionManager)
    {
        _container = container;
        _regionManager = regionManager;

    }

    public void Initialize()
    {
        _container.RegisterType<ILoginView, LoginView>();
        _container.RegisterType<ILoginViewModel, LoginViewModel>();
        _container.RegisterType<IDashboardView, DashboardView>();
        _container.RegisterType<IDashboardViewModel, DashboardViewModel>();

        _regionManager.RegisterViewWithRegion(RegionNames.DashboardRegion,
                                                typeof(LoginView));
        _regionManager.RegisterViewWithRegion(RegionNames.DashboardRegion,
                                                typeof(DashboardView));
    }
}

这是我的 bootstrapper.cs class :--

public class BootStrapper : UnityBootstrapper,IDisposable
{
    protected override DependencyObject CreateShell()
    {
        return Container.Resolve<Shell>();
    }

    protected override void InitializeShell()
    {
        base.InitializeShell();

        App.Current.MainWindow = (Window)Shell;
        App.Current.MainWindow.Show();
    }

    protected override void ConfigureModuleCatalog()
    {
        base.ConfigureModuleCatalog();

        Type moduleAType = typeof(ModuleDetailsModule);
        Type moduleNewForm = typeof(ModuleNewFormModule);
        Type moduleToolbarType = typeof(ModuleToolbarModule);
        Type moduleFooterType = typeof(ModuleFooterModule);
        Type moduleDashboardType = typeof(ModuleDashboardModule);
        Type moduleInvestmentType = typeof(ModuleInvestmentModule);
        Type moduleInvestmentDetailsType = typeof(ModuleInvestmentDetailsModule);

        ModuleCatalog.AddModule
        (
            new ModuleInfo()
            {
                ModuleName = moduleAType.Name,
                ModuleType = moduleAType.AssemblyQualifiedName,
                InitializationMode = InitializationMode.WhenAvailable
            }

        );
        ModuleCatalog.AddModule
        (
            new ModuleInfo()
            {
                ModuleName = moduleNewForm.Name,
                ModuleType = moduleNewForm.AssemblyQualifiedName,
                InitializationMode = InitializationMode.WhenAvailable
            }

        );

        ModuleCatalog.AddModule
        (
            new ModuleInfo()
            {
                ModuleName = moduleToolbarType.Name,
                ModuleType = moduleToolbarType.AssemblyQualifiedName,
                InitializationMode = InitializationMode.WhenAvailable
            }

        );

        ModuleCatalog.AddModule
        (
            new ModuleInfo()
            {
                ModuleName = moduleFooterType.Name,
                ModuleType = moduleFooterType.AssemblyQualifiedName,
                InitializationMode = InitializationMode.WhenAvailable
            }

        );

        ModuleCatalog.AddModule
        (
            new ModuleInfo()
            {
                ModuleName = moduleDashboardType.Name,
                ModuleType = moduleDashboardType.AssemblyQualifiedName,
                InitializationMode = InitializationMode.WhenAvailable
            }

        );

        ModuleCatalog.AddModule
            (
              new ModuleInfo()
              {
                  ModuleName = moduleInvestmentType.Name,
                  ModuleType = moduleInvestmentType.AssemblyQualifiedName,
                  InitializationMode = InitializationMode.WhenAvailable
              }
            );

        ModuleCatalog.AddModule
            (
            new ModuleInfo()
            {
                ModuleName = moduleInvestmentDetailsType.Name,
                ModuleType = moduleInvestmentDetailsType.AssemblyQualifiedName,
                InitializationMode = InitializationMode.WhenAvailable
            }
            );
    }

我的 LoginView.xaml.cs 文件是:

public partial class LoginView : UserControl,ILoginView
{
    [InjectionConstructor]
    public LoginView(LoginViewModel viewModel)
    {
        InitializeComponent();
        this.ViewModel = viewModel;
    }

    public IViewModel ViewModel
    {
        get
        {
            return (IViewModel)DataContext;
        }
        set
        {
            DataContext = value;
        }
    }
}

我的DashboardView.xaml.cs如下:

public partial class DashboardView : UserControl,IDashboardView
{
    DashboardViewModel viewModel = new DashboardViewModel();
    [InjectionConstructor]
    public DashboardView()
    {
        InitializeComponent();
        this.DataContext = viewModel;
        //this.ViewModel = viewModel;
    }

    public IViewModel ViewModel
    {
        get
        {
            return (IViewModel)DataContext;
        }
        set
        {
            DataContext = value;
        }
    }
}

我没有弄错我在哪里。任何帮助都是可观的。

这就是设置正确的数据上下文。

您似乎没有为仪表板视图设置数据上下文。因此,loginViewModel 成为仪表板视图的数据上下文。这是因为如果未明确设置,数据上下文是从 xaml 的父控件继承的。

尝试为内容控件设置数据上下文

    <ContentControl DataContext="{Binding DashborardVM}">
    <ContentControl.Template>
        <ControlTemplate TargetType="{x:Type ContentControl}">
            <Grid>
                <Border >
                    <ContentPresenter/>
                </Border>
            </Grid>
        </ControlTemplate>
    </ContentControl.Template>
    <local:DashboardView  Visibility="{Binding DashboardVisible, Converter={StaticResource BoolVisibilityConverter}}"/>
</ContentControl> 

否则您将必须按照格式

进行所有绑定
{Binding DashborardVM.DashboardVisible}
{Binding DashborardVM.property}

编辑 - 顺便说一句,如果您使用的是棱镜,请检查视图模型是否已正确注册,以便自动分配它们。 并且可能将可见性设置为

<local:DashboardView  Visibility="{Binding DashborardVM.DashboardVisible, Converter={StaticResource BoolVisibilityConverter}}"/>

会有所帮助,因为这里的数据上下文是 LoginViewmodel

我会尽量避免在 ViewModel 中过多地处理可见性。 相反,公开一个布尔值,例如登录并在您的视图中绑定到它。 您可以在那里使用 Style/DataTrigger 相应地更改可见性。

<Style x:Key="LoginVisibilityStyle" TargetType="StackPanel">
     <Style.Triggers>
          <DataTrigger Binding="{Binding LoggedIn}" Value="false">
              <Setter Property="Visibility" Value="Visible"/>
          </DataTrigger>
          <DataTrigger Binding="{Binding LoggedIn}" Value="true">
              <Setter Property="Visibility" Value="Collapsed"/>
          </DataTrigger>
     </Style.Triggers>
</Style>

如果您必须使用不同的 Controls DataContext,即 ViewModel,您可以这样做:

="{Binding DataContext.LoggedIn, UpdateSourceTrigger=PropertyChanged, RelativeSource= {RelativeSource FindAncestor, AncestorType={x:Type views:MainView}}}"