我在使用Caliburn Micro Conductor<>.Collection.OneActive
和MahApps.Metro HamburgerMenu
时遇到一些问题。来自few samples,但没有一个符合我的情况。
我的所有代码均可在this Github repository中找到。
我想在HamburgerMenu
中显示一组窗格。每个窗格都有一个标题和显示名称:
public interface IPane : IHaveDisplayName, IActivate, IDeactivate
{
PackIconModernKind Icon { get; }
}
就我而言,IPane
是使用PaneViewModel
实现的:
public class PaneViewModel : Screen, IPane
{
public PaneViewModel(string displayName, PackIconModernKind icon)
{
this.Icon = icon;
this.DisplayName = displayName;
}
public PackIconModernKind Icon { get; }
}
这有以下观点:
<UserControl x:Class="CaliburnMetroHamburgerMenu.Views.PaneView"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Padding="12"
Background="Pink">
<StackPanel Orientation="Vertical">
<TextBlock Text="Non-bound text" />
<TextBlock x:Name="DisplayName" FontWeight="Bold" />
</StackPanel>
</UserControl>
我的shell视图模型也很简单。它继承自Conductor<IPane>.Collection.OneActive
,并接收它添加到Items
集合的窗格列表:
public class ShellViewModel : Conductor<IPane>.Collection.OneActive
{
public ShellViewModel(IEnumerable<IPane> pages)
{
this.DisplayName = "Shell!";
this.Items.AddRange(pages);
}
}
现在,这对我来说非常模糊。这是摘自ShellView.xaml
:
<controls:HamburgerMenu
ItemsSource="{Binding Items, Converter={StaticResource PaneListToHamburgerMenuItemCollection}}"
SelectedItem="{Binding ActiveItem, Mode=TwoWay, Converter={StaticResource HamburgerMenuItemToPane}}">
<ContentControl cal:View.Model="{Binding ActiveItem}" />
<controls:HamburgerMenu.ItemTemplate>
<DataTemplate>
<Grid x:Name="RootGrid"
Height="48"
Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<iconPacks:PackIconModern
Grid.Column="0"
Kind="{Binding Icon}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="White" />
<TextBlock Grid.Column="1"
VerticalAlignment="Center"
FontSize="16"
Foreground="White"
Text="{Binding Label}" />
</Grid>
</DataTemplate>
</controls:HamburgerMenu.ItemTemplate>
</controls:HamburgerMenu>
为了完成这项工作,我依靠两个转换器(他们坦率地做了比他们应该做的更多)。一个转换器使用ICollection<IPane>
并使用HamburgerMenuItemCollection
创建HamburgerMenuIconItem
,其中Tag
现在包含使用视图模型和菜单项的class PaneListToHamburgerMenuItemCollection : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var viewModels = value as ICollection<IPane>;
var collection = new HamburgerMenuItemCollection();
foreach (var vm in viewModels)
{
var item = new HamburgerMenuIconItem();
item.Label = vm.DisplayName;
item.Icon = vm.Icon;
item.Tag = vm;
vm.Tag = item;
collection.Add(item);
}
return collection;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
属性的双向链接
Tag
只要SelectedItem
更改,第二个转换器就会使用class HamburgerMenuItemToPane : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((IPane)value)?.Tag;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((HamburgerMenuIconItem)value)?.Tag;
}
}
在视图模型和菜单项之间进行转换:
ShellViewModel
当我运行此代码并单击汉堡菜单中的项目时,页面每次都会切换。问题是,当应用程序首次运行时,没有选定的窗格,并且您无法使用OnViewAttached
中可用的任何激活替换设置(例如OnActivate
或Tag
,或者事件构造函数),因为挂钩ShellViewModel
的转换器代码尚未运行。
我对工作解决方案的要求:
{% block body %}
<div class="container">
<h3>List of products</h3>
<table class="table table-striped">
<thead>
<tr>
<th>Product</th>
<th>Description</th>
<th>Size</th>
<th>Charges</th>
<th>Price</th>
<th>Actions</th>
<th>Desactivation</th>
</tr>
</thead>
<tbody>
{% for catalogue in catalogues %}
<tr class="table">
<td>{{ catalogue.product}} </td>
<td>{{ catalogue.description }} </td>
<td>{{ catalogue.size}} </td>
<td>{{ catalogue.charge }} </td>
<td>{{ catalogue.price }}</td>
<td>
<a href="{{ path('catalogue_list_edit', { 'id': catalogue.id }) }}"><span class="glyphicon glyphicon-edit"></span></a>
<a href="{{ path('catalogue_list_delete', { 'id': catalogue.id }) }}"><span class="glyphicon glyphicon-remove"></span></a>
</td>
<td><input type="checkbox" name="boutton35" value="Desactivation" />
</td>
</tr>
{% else %}
{% endfor %}
</tbody>
</table>
{% endblock %}
请参阅the GitHub repository以获取可立即运行的解决方案。
答案 0 :(得分:0)
我认为问题是由控件中的HamburgerMenu_Loaded
方法引起的。如果在加载控件之前存在选定的项目,则替换汉堡包菜单的内容:
private void HamburgerMenu_Loaded(object sender, RoutedEventArgs e)
{
var selectedItem = this._buttonsListView?.SelectedItem ?? this._optionsListView?.SelectedItem;
if (selectedItem != null)
{
this.SetCurrentValue(ContentProperty, selectedItem);
}
}
在您的情况下,ContentControl
被删除,Conductor
无法正常工作。
我试图通过将代码更改为以下内容来确定是否可以直接在MahApps中更改此行为:
if (this.Content != null)
{
var selectedItem = this._buttonsListView?.SelectedItem ?? this._optionsListView?.SelectedItem;
if (selectedItem != null)
{
this.SetCurrentValue(ContentProperty, selectedItem);
}
}