属性 与多个用户控件级别的 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}}}"
我有两个用户控件(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}}}"