2017-07-30 29 views
3

我是那种新手的& MVVM &卡利所以请你原谅:)WPF Caliburn.Micro和TabControl的 - 改变选项卡,在WPF不改变模型

我有一个问题与动态创建的模型结合的TabControl 。自定义的Tabcontrol被正确创建,但改变标签不切换用来绑定“视图”视图模型(我使用的视图模型第一种方法)

我做了我的解决方案立足于这样一个问题:WPF Caliburn.Micro and TabControl with UserControls issue

这是我的模型定义:

public interface IMainScreenTabItem : IScreen 
{ 
} 

public class MainViewTestTabsViewModel : Conductor<IMainScreenTabItem>.Collection.OneActive 
{ 
    public MainViewTestTabsViewModel(IEnumerable<IMainScreenTabItem> tabs) 
    { 
     Items.Add(new ViewTabModel("Foo1")); 
     Items.Add(new ViewTabModel("Foo2")); 
     Items.AddRange(tabs); 
    } 
} 

public sealed class ViewTabModel : Screen, IMainScreenTabItem 
{ 
    public ViewTabModel(string displayName) 
    { 
     DisplayName = displayName; 
    } 
} 

这里是视图MainViewTestTabsView:

<UserControl x:Class="TestWpfApp.Views.MainViewTestTabsView" 
    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:local="clr-namespace:TestWpfApp.Views" 
    xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" 
    xmlns:viewModels="clr-namespace:TestWpfApp.ViewModels" 
    xmlns:cal="http://www.caliburnproject.org" 
    mc:Ignorable="d" Width="500" Height="500"> 
<Grid> 
    <TabControl Name="Items"> 
     <TabControl.ContentTemplate> 
      <DataTemplate> 
       <StackPanel> 
        <Label cal:Bind.Model="{Binding}" x:Name="DisplayName" Height="200" Width="200" /> 
       </StackPanel> 
      </DataTemplate> 
     </TabControl.ContentTemplate> 
    </TabControl> 
</Grid> 

我想实现的目标是让TabControl带有许多选项卡。每个选项卡具有相同的“视图”(在DataTemplate中声明),但绑定此视图我想使用不同的viewModels(具体 - 相同的模型类[ViewTabModel],但具有不同的数据)

选项卡的大小是在运行时声明以及应该在ViewTabModel模型中的数据。

在下面的例子 - 我有两个标签,但改变他们是不会改变的标签(我把所有的时间:“Foo1”标签,即使我点击“foo2的”标签)

我用卡利。微观作为框架 - 与autofac bootstrap(如果它很重要) 而我使用propertyChanged.Fody(https://github.com/Fody/PropertyChanged)省略所有在viewmodels中的属性changed stuff。

我在做什么错?

=== UPDATE ===

附加最小再现解决方案:

https://wetransfer.com/downloads/0b909bfd31a588dda99655f366eddad420170801192103/1d094a

普莱舍,救命啊! :)

===更新2 ===

什么不清楚关于我的问题?:)不过没有意见,没有与它赏金anwsers事件。

===更新3 ===

我已经发布完整视图页面(XAML)和完整的模型代码(这仅仅是这个)

我还张贴AppBoostraper.cs和AppWindowManager.cs(但我想这是irrelevat这里)

AppBoostrapper.cs

using Autofac; 
using TestWpfApp.ViewModels; 

namespace TestWpfApp { 
    using System; 
    using System.Collections.Generic; 
    using Caliburn.Micro; 

    public class AppBootstrapper : CaliburnMetroAutofacBootstrapper<MainViewTestTabsViewModel> 
    { 
     protected override void ConfigureContainer(ContainerBuilder builder) 
     { 
      builder.RegisterType<AppWindowManager>().As<IWindowManager>().SingleInstance(); 
      var assembly = typeof(ShellViewModel).Assembly; 
      builder.RegisterAssemblyTypes(assembly) 
       .Where(item => item.Name.EndsWith("ViewModel") && item.IsAbstract == false) 
       .AsSelf() 
       .SingleInstance(); 
     } 
    } 
} 

它继承CaliburnMetroAutofacContainer(https://github.com/ziyasal/Caliburn.Metro

AppWindowsManager。CS

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using Caliburn.Metro.Core; 
using MahApps.Metro.Controls; 

namespace TestWpfApp 
{ 
    public class AppWindowManager : MetroWindowManager 
    { 
     public override MetroWindow CreateCustomWindow(object view, bool windowIsView) 
     { 
      if (windowIsView) 
      { 
       return view as ShellView; 
      } 

      return new ShellView 
      { 
       Content = view 
      }; 
     } 
    } 
} 

=== UPDATE 4 === Apprently,从改变控制:

CAL:Bind.Model = “{结合}” ×:名称= “DisplayName的”

到:

内容= “{结合DisplayName的}”

做了工作。虽然我不太清楚为什么?

现在我想要做的完全一样。只有这一次,我希望我的看法被束缚。所以ViewModel完全一样。但是,这一次:

<UserControl x:Class="TestWpfApp.Views.MainViewTestTabsView" 
    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:local="clr-namespace:TestWpfApp.Views" 
    xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" 
    xmlns:viewModels="clr-namespace:TestWpfApp.ViewModels" 
    xmlns:cal="http://www.caliburnproject.org" 
    mc:Ignorable="d" Width="500" Height="500"> 
<Grid> 
    <TabControl Name="Items"> 
     <TabControl.ContentTemplate> 
      <DataTemplate> 
       <StackPanel> 
        <local:ViewTab cal:Bind.Model="{Binding}" /> 
       </StackPanel> 
      </DataTemplate> 
     </TabControl.ContentTemplate> 
    </TabControl> 
</Grid> 

和ViewTab视图

MainViewTestTabsView是:

<UserControl x:Class="TestWpfApp.Views.ViewTab" 
    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:local="clr-namespace:TestWpfApp.Views" 
    xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" 
    xmlns:viewModels="clr-namespace:TestWpfApp.ViewModels" 
    xmlns:cal="http://www.caliburnproject.org" 
    mc:Ignorable="d" Width="300" Height="300"> 
<Grid> 
    <StackPanel> 
     <Label x:Name="DisplayName"></Label> 
    </StackPanel> 
</Grid> 

===更新5 =>幸福的最后=== 我已被消化我应该坚持ViewModel的第一次会议(正如我宣称的那样使用)和我的尝试是somhow首先查看。所以,我把它改为:

<ContentControl cal:View.Model="{Binding ActiveItem}" /> 

但没有什么是呈现然后

我若这样的:

<ContentControl cal:View.Model="{Binding}" /> 

有只说消息:“对于无法找到的看法: [my_namspece] .ViewTabModel 这很奇怪,让我思考,也许我不会坚持这个惯例,而且这是真的......

我的模特叫:

ViewTabModel

而应该是:

ViewTabViewModel

正好与观点同样的事情。它应该被称为:

ViewTabView.xaml

之后,这样的结构:

<ContentControl cal:View.Model="{Binding}" /> 

工作正常!谢谢arcticwhite和grek40领导我这种解决方案

+0

是否缺少结合的模式? – Ramankingdom

+0

我用Caliburn很久回来。你有没有尝试ActivateItem(viewmodel在这里)? – Ramankingdom

+0

关于变化的标签,你需要激活视图使用ActivateItem – Ramankingdom

回答

1

现在我有一些时间来测试你的样本项目......为我评论,你应该选择正确的绑定类型...

All About Actions,我想会有其他文件来源周围,上市相同的基本信息:

  • Bind.Model - 视图 - 一 - 集的的Action.Target和DataContext的属性来指定实例。将约定 应用于视图。字符串值用于解析来自IoC容器的实例。 (在Window/UserControl/Page的根节点上使用)
  • Bind.ModelWithoutContext - View-First - 将Action.Target设置为指定的实例。将惯例应用于视图。 (在DataTemplate中使用 。)
  • View.Model - ViewModel-First - 查找指定VM实例的视图并将其注入内容站点。将VM 设置为Action.Target和DataContext。将惯例应用于 视图。

至于说,我不是一个专家卡利,所以我不得不尝试...第二个选项最好看着我(“的DataTemplate内使用”),所以这里是工作结果:

<Label cal:Bind.Model="{Binding}" x:Name="DisplayName" Height="200" Width="200" /> 

更换到

<Label cal:Bind.ModelWithoutContext="{Binding}" x:Name="DisplayName" Height="200" Width="200" /> 

及其工作。

其实,我建议引入周围的StackPanel,而不是(在DataTemplate中根)

<StackPanel cal:Bind.ModelWithoutContext="{Binding}"> 
    <Label x:Name="DisplayName" Height="200" Width="200" /> 
</StackPanel> 
+0

我设法以另一种方式运行它:)通过使用:它不工作在开始(我试过这种方式 - 甚至在我发布SOF的问题之前,但它在主要问题中没有工作(出于某种原因)更多。 我如何在两个人之间分享赏金?因为你和arctiwhite帮了我很多。 – Piotr

+0

你不能分裂赏金。然而,你可以接受你认为最适合你的问题的答案,并且奖励另一个答案以关注你的问题;) – grek40

+0

是的,我已经在Stack meta上找到了关于这个主题的讨论。我不同意他们结论的结果。 arcticwhite帮助我解决了问题的初始阶段。你帮我指导了我最后的结论。这两个答案都不是完整的,复杂的和最终的。唉,丢掉50个声誉点是可耻的。抱歉的家伙 - 我必须掷骰子:)谢谢无论如何 – Piotr

2

好了... 我已经与Caliburn.Micro工作,所以我可以说我有一些经验,而不是一个职业球员,但我设法使它工作。

你MainViewTestTabsViewModel.cs:

public interface IMainScreenTabItem : IScreen 
    { 
    } 

    public class MainViewTestTabsViewModel : Conductor<IMainScreenTabItem>.Collection.OneActive 
    { 
     public MainViewTestTabsViewModel(IEnumerable<IMainScreenTabItem> tabs) 
     { 

      Items.Add(new ViewTabModel() {DisplayName = "Test"}); 
      Items.Add(new ViewTabModel() { DisplayName = "Test2" }); 
      Items.Add(new ViewTabModel() { DisplayName = "Test3" }); 
      Items.AddRange(tabs); 
     } 
    } 

    public class ViewTabModel : Screen, IMainScreenTabItem 
    { 
     public ViewTabModel() 
     { 

     } 
    } 

而且你MainViewTestTabsView.xaml

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:local="clr-namespace:TestWpfApp.ViewModels" 
    xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" 
    xmlns:viewModels="clr-namespace:TestWpfApp.Views" 
    xmlns:cal="http://www.caliburnproject.org" 
    mc:Ignorable="d" Width="500" Height="500"> 
    <Grid> 
     <TabControl x:Name="Items" > 
      <TabControl.ContentTemplate> 
       <DataTemplate> 
        <StackPanel> 
         <Label cal:Bind.ModelWithoutContext="{Binding}" x:Name="DisplayName" Height="200" Width="200"/> 
        </StackPanel> 
       </DataTemplate> 
      </TabControl.ContentTemplate> 
     </TabControl> 
    </Grid> 
    </UserControl> 

附:为什么我在构造函数中删除了displayName变量...因为您不需要它,所以它已经在Caliburn:Micro.Screen中作为属性。

编辑#2 该公约将工作,只需添加cal:Bind.ModelWithoutContext="{Binding}"Label(编辑答案)内。

+0

是的,它的工作 - 但我不知道为什么。 caliburn.micro不应该按照约定来绑定数据(毕竟,名称是DisplayName)?它的确可以修复最小的复制范例 - 但它仍然不能解决我真正的问题,这有点复杂。我会更新我的问题。 (我需要的是绑定我的自定义viewModel与视图) – Piotr

+0

所以你说的解决这个问题的正确方法是使用显式绑定('Content =“{Binding DisplayName}”'),而不是依靠校准约定。微?我知道这是可能的,但我认为它打破了原来的想法,特别是因为'DisplayName'被认为只是一个相当复杂的实际项目结构的最小例子。 €dit:Piotr评论比我快:) – grek40

+0

唯一令我惊讶的是 - 不依赖convention =正常工作。我无法理解它;) 只需再走一步,我就准备好了。我只需要改变这个简单的模板来使用声明的视图(以及如何绑定它)更新4将在一分钟内 – Piotr