2017-07-30 191 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