如何使用Caliburn在MVVM中重用新视图.微观和微观



我正在测试动态修改网格控制结构的可能性(例如行/列的数量)。

我正在使用最新版本的Caliburn。微型和Ninject,并使用GridHelpers(我已经修改)有可能绑定行和列的数量。

我的应用程序的完整代码可在Github

我已经创建了一个用户控件MyGridView:

<UserControl x:Class="GridHelpersSample.MyGridView"
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:gh="clr-namespace:GridHelpers;assembly=GridHelpers"
xmlns:cal="http://www.caliburnproject.org"
xmlns:local="clr-namespace:GridHelpersSample"
mc:Ignorable="d" 
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<ItemsControl ItemsSource="{Binding ButtonViewModels}">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Row" Value="{Binding GridRow}" />
<Setter Property="Grid.Column" Value="{Binding GridColumn}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate >
<DataTemplate >
<Button cal:Message.Attach="[Event Click] = [Action OnButtonClick($dataContext)]"
Content="{Binding Content}"/>
</DataTemplate >
</ItemsControl.ItemTemplate >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid ShowGridLines="true" 
gh:GridHelpers.RowCount = "{Binding RowCount, Mode=TwoWay}"
gh:GridHelpers.ColumnCount = "{Binding ColumnCount, Mode=TwoWay}"
gh:GridHelpers.StarRows = "{Binding StarRows, Mode=TwoWay}"
gh:GridHelpers.StarColumns = "{Binding StarColumns, Mode=TwoWay}"
gh:GridHelpers.PixelRows = "{Binding PixelRows, Mode=TwoWay}"
gh:GridHelpers.PixelColumns = "{Binding PixelColumns, Mode=TwoWay}" >
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- Now define a container that will host the ItemsControl -->
<!--<ItemsControl.ItemsPanel >
<ItemsPanelTemplate >
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate >
</ItemsControl.ItemsPanel >-->
</ItemsControl >
</Grid>
</UserControl>

关联的视图模型:

using Caliburn.Micro;
namespace GridHelpersSample
{
public class MyGridViewModel : Screen
{
public BindableCollection<ButtonViewModel> ButtonViewModels { get; set; }
public MyGridViewModel(Main2ViewModel main2ViewModel)
{
RowCount = main2ViewModel.RowCount;
ColumnCount = main2ViewModel.ColumnCount;
StarRows = main2ViewModel.StarRows;
StarColumns = main2ViewModel.StarColumns;
PixelRows = main2ViewModel.PixelRows;
PixelColumns = main2ViewModel.PixelColumns;
ButtonViewModels = main2ViewModel.ButtonViewModels;
}
#region datas for defining grid
private string rowCount;
public string RowCount
{
get { return rowCount; }
set
{
rowCount = value;
NotifyOfPropertyChange(() => RowCount);
}
}
private string columnCount;
public string ColumnCount
{
get { return columnCount; }
set
{
columnCount = value;
NotifyOfPropertyChange(() => ColumnCount);
}
}
private string starRows;
public string StarRows
{
get { return starRows; }
set
{
starRows = value;
NotifyOfPropertyChange(() => StarRows);
}
}
private string starColumns;
public string StarColumns
{
get { return starColumns; }
set
{
starColumns = value;
NotifyOfPropertyChange(() => StarColumns);
}
}
private string pixelRows;
public string PixelRows
{
get { return pixelRows; }
set
{
pixelRows = value;
NotifyOfPropertyChange(() => PixelRows);
}
}
private string pixelColumns;
public string PixelColumns
{
get { return pixelColumns; }
set
{
pixelColumns = value;
NotifyOfPropertyChange(() => PixelColumns);
}
}
#endregion
public void OnButtonClick(ButtonViewModel context)
{
}
}
}

Main2View有一个内容控件和所有的设置来定义在usercontrol中定义的网格结构。

<Window x:Class="GridHelpersSample.Main2View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:gh="clr-namespace:GridHelpers;assembly=GridHelpers"
xmlns:cal="http://www.caliburnproject.org"       
xmlns:local="clr-namespace:GridHelpersSample"
mc:Ignorable="d"
Title="Main2View" Height="600" Width="1000">
<Window.Resources>
<Style x:Key="LabelStyle" TargetType="Label">
<Setter Property="Width" Value="120" />
<Setter Property="Margin" Value="5" />
<Setter Property="FontSize" Value="16" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="Blue" />
</Style>
<Style x:Key="TextBoxStyle" TargetType="TextBox">
<Setter Property="Width" Value="120" />
<Setter Property="Margin" Value="5" />
<Setter Property="FontSize" Value="16" />
<Setter Property="FontWeight" Value="Regular" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<!--<Setter Property="cal:Message.Attach" Value="[Event LostFocus] = [Action TextBox_LostFocus($source, $this)]" />-->
<Style.Triggers>
<Trigger Property="Name" Value="RowCount">
<Setter Property="Width" Value="30"/>
</Trigger>
<Trigger Property="Name" Value="ColumnCount">
<Setter Property="Width" Value="30"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid x:Name="MainGrid"
gh:GridHelpers.RowCount="2"
gh:GridHelpers.ColumnCount="1"
gh:GridHelpers.StarRows="1"
gh:GridHelpers.StarColumns="*">
<StackPanel Orientation="Vertical" Grid.Row="0" >
<Separator />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Label Content="RowCount:" Style="{StaticResource LabelStyle}" />
<TextBox x:Name="RowCount" Style="{StaticResource TextBoxStyle}" />
<Label Content="StarRows:" Style="{StaticResource LabelStyle}" />
<TextBox x:Name="StarRows" Style="{StaticResource TextBoxStyle}" />
<Label Content="PixelRows:" Style="{StaticResource LabelStyle}" />
<TextBox x:Name="PixelRows" Style="{StaticResource TextBoxStyle}" />
<Button x:Name="Valider" Content="Valider la saisie" Width="100" 
Margin="30,20,0,-20" />
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Label Content="ColumnCount:" Style="{StaticResource LabelStyle}" />
<TextBox x:Name="ColumnCount" Style="{StaticResource TextBoxStyle}" />
<Label Content="StarColumns:" Style="{StaticResource LabelStyle}" />
<TextBox x:Name="StarColumns" Style="{StaticResource TextBoxStyle}" />
<Label Content="PixelColumns:" Style="{StaticResource LabelStyle}" />
<TextBox x:Name="PixelColumns" Style="{StaticResource TextBoxStyle}" />
<Button Width="100" Visibility="Hidden" Height="0" Margin="30,0,0,0"/>
</StackPanel>
<Separator />
</StackPanel>
<ContentControl x:Name="myGridViewModel" Grid.Row="1"/>
</Grid>
</Window>

Main2ViewModel的代码:

using Caliburn.Micro;
using Ninject;
using Ninject.Syntax;
using System.Collections.Generic;
namespace GridHelpersSample
{
public class Main2ViewModel : Screen
{
private readonly IResolutionRoot _resolutionRoot;
private readonly IKernel _kernel;
public BindableCollection<ButtonViewModel> ButtonViewModels { get; set; }
public MyGridViewModel myGridViewModel { get; set; }
public Main2ViewModel(IResolutionRoot resolutionRoot, IKernel kernel) 
{
_resolutionRoot = resolutionRoot;
_kernel = kernel;
RowCount = "3";
ColumnCount = "3";
StarRows = "*";
StarColumns = "*";
PixelRows = "";
PixelColumns = "";
AddNewContent();
}
#region datas for defining grid
private string rowCount;
public string RowCount
{
get { return rowCount; }
set
{
rowCount = value;
NotifyOfPropertyChange(() => RowCount);
}
}
private string columnCount;
public string ColumnCount
{
get { return columnCount; }
set
{
columnCount = value;
NotifyOfPropertyChange(() => ColumnCount);
}
}
private string starRows;
public string StarRows
{
get { return starRows; }
set
{
starRows = value;
NotifyOfPropertyChange(() => StarRows);
}
}
private string starColumns;
public string StarColumns
{
get { return starColumns; }
set
{
starColumns = value;
NotifyOfPropertyChange(() => StarColumns);
}
}
private string pixelRows;
public string PixelRows
{
get { return pixelRows; }
set
{
pixelRows = value;
NotifyOfPropertyChange(() => PixelRows);
}
}
private string pixelColumns;
public string PixelColumns
{
get { return pixelColumns; }
set
{
pixelColumns = value;
NotifyOfPropertyChange(() => PixelColumns);
}
}
#endregion
public void Valider()
{            
AddNewContent();
}
public List<ButtonViewModel> CreateButton()
{
var myView = _resolutionRoot.Get<Main2View>();
var t = myView.MainGrid;
var list = new List<ButtonViewModel>();
for (int i = 0; i < int.Parse(RowCount); i++)
{
for (int j = 0; j < int.Parse(ColumnCount); j++)
{
var button = new ButtonViewModel
{
Content = $"R{i} C{j}",
GridRow = i,
GridColumn = j
};
list.Add(button);
}
}
return list;
}
private void AddNewContent()
{
ButtonViewModels = new BindableCollection<ButtonViewModel>(CreateButton());
myGridViewModel = new MyGridViewModel(this);
}
}
}

在视图/视图模型的初始化期间一切都很好,但是当我改变RowCount或RowColumn的值并单击按钮时,问题就开始了。

我正在等待新视图的初始化,但事实并非如此,视图MyGridView没有重新加载..

这是boostrapper:

using Caliburn.Micro;
using Ninject;
using System;
using System.Collections.Generic;
using System.Windows;
namespace GridHelpersSample
{
public class Bootstrapper : BootstrapperBase
{
private IKernel kernel;
public Bootstrapper()
{
Initialize();
}
protected override void Configure()
{
kernel = new StandardKernel();
kernel.Bind<IWindowManager>().To<WindowManager>().InSingletonScope();
kernel.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope();
kernel.Bind<MyGridViewModel>().ToSelf().InTransientScope();
//kernel.Bind<MyGridViewModel>().ToSelf().InSingletonScope();
var bindings0 = kernel.GetBindings(typeof(MyGridViewModel));
//var bindings1 = kernel.GetBindings(typeof(MainViewModel));
}
protected override async void OnStartup(object sender, StartupEventArgs e)
{
await DisplayRootViewForAsync<Main2ViewModel>();
}
protected override object GetInstance(Type service, string key)
{
return kernel.Get(service);
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return kernel.GetAll(service);
}
protected override void BuildUp(object instance)
{
kernel.Inject(instance);
}
}
}

我没有到达重新启动一个新的视图,即使我使用InTransientScope()指示使用view..的新实例。但也许我错过了什么…

无论如何,似乎应用程序有问题,因为当我关闭主视图时,调试器没有完成,我必须用VS2022

中的红色按钮停止应用程序我已经测试了使用Unbind,但是没有成功

private void AddNewContent()
{
ButtonViewModels = new BindableCollection<ButtonViewModel>(CreateButton());
if (myGridViewModel == null)
{
myGridViewModel = new MyGridViewModel(this);
return;
}
//_kernel.Unbind<MyGridViewModel>();
_kernel.Unbind<MyGridView>();
//_kernel.Bind<MyGridViewModel>().To<MyGridViewModel>();
_kernel.Bind<MyGridView>().To<MyGridView>();
myGridViewModel = new MyGridViewModel(this);
}

我已经找到了解决方案:

Main2ViewModel,只是重构我的变量myGridViewModel与NotifyOfPropertyChange():

private MyGridViewModel _myGridViewModel;
public MyGridViewModel myGridViewModel
{
get { return _myGridViewModel; }
set
{
_myGridViewModel = value;
NotifyOfPropertyChange(() => myGridViewModel);
}
}

所以我可以这样写AddNewContent方法:

private void AddNewContent()
{
ButtonViewModels = new BindableCollection<ButtonViewModel>(CreateButton());
myGridViewModel = new MyGridViewModel(this);
}

所以在bootstrapper.cs文件中,不需要绑定MyGridViewModel:

protected override void Configure()
{
kernel = new StandardKernel();
kernel.Bind<IWindowManager>().To<WindowManager>().InSingletonScope();
kernel.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope();
}

当我退出应用程序时就没有问题了

最新更新