好的,我尝试重建一些东西来模拟你的行为。并想出了这个,它应该非常接近你的行为。
我添加了一个InverseToBooleanConverter,它以与布尔相反的方式显示可见性(false = Visible)。这有助于切换的东西
我为来自整数的 GridLength(您的身高)添加了一个转换器。我冒昧地创建了一个 Enum,它代表 Show 和 Hide 的值。
重要的规则是保持你的 ViewModel 没有以 System.Windows 或任何与视图相关的东西开头的命名空间。
我以某种方式对您的属性和 PropertyNotification-Stuff 进行了排序。目标是尽可能保持紧实和精简。所以对于这段代码,我只能从属性本身调用 OnPropertyChanged。
对我来说,TaskListView 是一个Control 并且将拥有它自己的ListOfTaskViewModel(带有行为)和它的任务集合(取决于其中的复杂性。这也可能是一个ObservableList<TaskItemViewModel>)
这同样适用于MeetingListView,它是MeetingListViewModel。
现在重要的是在哪里以及如何加载数据。我可以考虑一个服务,它至少有两个方法GetTasksForCaseID 和GetMeetingsForCaseID,可以注入 ViewModel 或者可以传递加载的数据。我更喜欢让事情保持独立,并会使用EventAggregator 或Messenger 之类的东西来通知ViewModel,并将匹配的ID 作为有效负载。并让ViewModel 负责获取数据。但这取决于并且由于我没有足够的关于您的上下文的信息,这超出了示例的范围。但我希望你能明白。
这就是 MainViewModel 类
同样的事情也适用于日历中的实际事件和亮点内容。它应该在一个自己的 ViewModel 中与自己的视图控件分开以保持干净。
public class MainViewModel:INotifyPropertyChanged
{
public MainViewModel()
{
Init();
}
public enum Calendar{
ShowCalendarMaxLength = 145,
HideCalenderHeight = 325,
}
private MeetingsListViewModel _listOfMeetingsViewModel;
public MeetingsListViewModel ListOfMeetingsViewModel {
get { return _listOfMeetingsViewModel; }
set
{
if (_listOfMeetingsViewModel != value)
{
_listOfMeetingsViewModel = value;
OnPropertyChanged("ListOfMeetings");
}
}
}
public TaskListViewModel _listOfTasksViewModel;
public TaskListViewModel ListOfTasksViewModel {
get{return _listOfTasksViewModel;}
set {
if (_listOfTasksViewModel != value)
{
_listOfTasksViewModel = value;
OnPropertyChanged("ListOfTasks");
}
}
}
private Calendar _calendarEventListBoxHeight;
public Calendar CalendarEventListBoxHeight
{
get { return _calendarEventListBoxHeight; }
set
{
if (_calendarEventListBoxHeight != value)
{
_calendarEventListBoxHeight = value;
OnPropertyChanged("CalendarEventListBoxHeight");
}
}
}
private bool _showCalendar;
public bool ShowCalendar
{
get { return _showCalendar; }
set {
if (_showCalendar != value)
{
_showCalendar = value;
OnPropertyChanged("ShowCalendar");
}
}
}
private bool _showTasks;
public bool ShowTasks
{
get { return _showTasks; }
set
{
if (_showTasks != value)
{
_showTasks = value;
OnPropertyChanged("ShowTasks");
}
}
}
private bool _showMeetings;
public bool ShowMeetings
{
get { return _showMeetings; }
set
{
if (_showMeetings != value)
{
_showMeetings = value; OnPropertyChanged("ShowMeetings");
}
}
}
public void ShowCalendarAction()
{
ShowCalendar = true;
CalendarEventListBoxHeight = Calendar.ShowCalendarMaxLength;
}
public void HideCalendarAction()
{
ShowCalendar = false;
CalendarEventListBoxHeight = Calendar.HideCalenderHeight;
}
public void ShowMeetingsAction()
{
ShowTasks = false;
ShowMeetings = true;
}
public void ShowTasksAction() {
ShowMeetings = false;
ShowTasks = true;
}
private void Init()
{
ShowCalendar = true;
CalendarEventListBoxHeight = Calendar.ShowCalendarMaxLength;
ShowMeetings = true;
ShowTasks = false;
ListOfMeetingsViewModel = new MeetingsListViewModel();
ListOfTasksViewModel = new TaskListViewModel();
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
这就是 XAML。
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:WpfApplication1.Converters"
xmlns:vm="clr-namespace:WpfApplication1.ViewModels"
xmlns:cal="http://www.caliburnproject.org"
xmlns:views="clr-namespace:WpfApplication1.Views"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Title="MainWindow" Height="350" Width="525"
>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="VisibilityConverter"/>
<conv:InverseBooleanConverter x:Key="InverseVisibilityConverter"/>
<conv:GridViewLengthConverter x:Key="LengthConverter" />
</Window.Resources>
<Window.DataContext>
<vm:MainViewModel />
</Window.DataContext>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Calendar Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0,0,0,0"
Visibility="{Binding Path=ShowCalendar, Mode=TwoWay,Converter={StaticResource VisibilityConverter}}"
>
</Calendar>
<Button Margin="0,12,0,0"
FontSize="15"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Content="Show Calendar"
Visibility="{Binding Path=ShowCalendar,Mode=TwoWay,Converter={StaticResource InverseVisibilityConverter}}"
ToolTip="ShowCalendar">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="ShowCalendarAction" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Margin="0,32,0,0"
FontSize="15"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Visibility="{Binding Path=ShowCalendar,Mode=TwoWay,Converter={StaticResource VisibilityConverter}}"
Content="Hide Calendar"
ToolTip="HideCalendarButtonClick">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="HideCalendarAction" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Margin="0,5,0,0"
Grid.Row="1"
Grid.Column="0"
FontSize="15"
HorizontalAlignment="Left"
Visibility="{Binding Path=ShowMeetings,Mode=TwoWay,Converter={StaticResource InverseVisibilityConverter}}"
Content="Show Meetings"
ToolTip="ShowMeetingsButtonClick">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="ShowMeetingsAction" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Margin="20,5,0,0"
Grid.Row="1"
Grid.Column="0"
FontSize="15"
Grid.ColumnSpan="3"
HorizontalAlignment="Left"
Visibility="{Binding Path=ShowTasks,Mode=TwoWay,Converter={StaticResource InverseVisibilityConverter}}"
Content="Show Tasks;"
ToolTip="ShowTasksButtonClick">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="ShowTasksAction" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Grid Grid.Row="2"
Grid.RowSpan="3"
Grid.Column="0"
Grid.ColumnSpan="2"
MaxHeight="{Binding Path=CalendarEventListBoxHeight, Mode=TwoWay, Converter={StaticResource LengthConverter }}"
Visibility="{Binding Path=ShowMeetings, Mode=TwoWay,Converter={StaticResource VisibilityConverter}}"
>
<views:MeetingsListView DataContext="{Binding Path=ListOfMeetingsViewModel,Mode=TwoWay}">
</views:MeetingsListView>
</Grid>
<Grid Grid.Row="2"
Grid.RowSpan="3"
Grid.Column="0"
Grid.ColumnSpan="2"
MaxHeight="{Binding Path=CalendarEventListBoxHeight, Converter={StaticResource LengthConverter }}"
Visibility="{Binding Path=ShowTaks,Converter={StaticResource LengthConverter}}"
>
<views:TaskListView DataContext="{Binding Path=ListOfTasksViewModel,Mode=TwoWay}" />
</Grid>
</Grid>
</Grid>
</Window>
为了完整起见,这两个转换器:
InverseBooleanToVisibiltyConverter
public class InverseBooleanConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (targetType != typeof(Visibility))
throw new InvalidOperationException("The target must be a boolean");
if (!(bool)value)
{
return Visibility.Visible;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
#endregion
}
GridViewLengthConverter
class GridViewLengthConverter:IValueConverter{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double val = (int)value;
GridLength gridLength = new GridLength(val);
return gridLength;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
GridLength val = (GridLength)value;
return val.Value;
}
}
我想您可以通过使用更少的布尔值优化切换行为来删除一些代码 =)...
//编辑:我坚信问题出在您显示的代码之外。特别是加载和交换部分或您在评论中描述为“更复杂的功能”的情况下 ViewMode。尽管如此,因为您已经有了一个 IsCaseLoaded-Property。我假设您正在这里进行一些异步数据获取。 MVVM 的异步/等待也可能很棘手。尤其是在将 UI 相关操作与后台操作混合时。附上你会发现一些有用的链接如何处理异步代码和 MVVM。本系列展示了 async-bindable-notification-properties、异步 IComannd 实现和异步服务的方法。
异步编程:异步 MVVM 应用程序的模式:数据绑定
https://msdn.microsoft.com/en-us/magazine/dn605875.aspx
异步编程:异步 MVVM 应用程序的模式:命令
https://msdn.microsoft.com/en-us/magazine/dn630647.aspx
异步编程:异步 MVVM 应用程序的模式:服务
https://msdn.microsoft.com/en-us/magazine/dn683795.aspx
希望对您有所帮助...