在WPF中的视图中共享控件实例

时间:2012-02-21 12:44:42

标签: wpf xaml mvvm

我在使用wpf标签控件时遇到了一些问题。不确定问题的标题是否正确我会根据答案对其进行改进。

我想创建一个简单的面板系统。我想注入我的“panel viewModel”2视图模型

  • MainViewModel将显示为主区域
  • PanelViewModel将显示为视图右侧的面板

默认情况下隐藏panelViewModel,并在需要时按钮将其显示在主视图模型的顶部

视图如下所示:

<UserControl.Resources>
 <DataTemplate x:Key="MainWindowTemplate" DataType="{x:Type UserControl}">
  <ContentPresenter Content="{Binding DataContext.MainViewModel, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
 </DataTemplate>
</UserControl.Resources>

<Grid>

 <Grid Visibility="{Binding IsPanelHidden, Converter={StaticResource bool2VisibilityConverter}}">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="Auto"/>
  </Grid.ColumnDefinitions>

  <ContentControl Grid.Column="0" ContentTemplate="{StaticResource MainWindowTemplate}" />

  <Button Grid.Column="1" Content="{Binding PanelTitle}" Command="{Binding Path=ShowPanelCommand}">
    <Button.LayoutTransform>
      <RotateTransform Angle="90"/>
    </Button.LayoutTransform>
  </Button>
 </Grid>

<Grid Visibility="{Binding IsPanelHidden, Converter={StaticResource revertBool2VisibilityConverter}}">

  <ContentControl ContentTemplate="{StaticResource MainWindowTemplate}" />

  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="0.5*"/>
    </Grid.ColumnDefinitions>

    <Border Grid.Column="2" VerticalAlignment="Stretch" Background="Red" >
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto"/>
          <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Border HorizontalAlignment="Stretch">
          <Grid HorizontalAlignment="Stretch">
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="*"/>
              <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Text="{Binding PanelTitle}" Margin="5,5,0,2" HorizontalAlignment="Left"></TextBlock>
            <StackPanel Grid.Column="1" Orientation="Horizontal" Margin="0,0,5,0" HorizontalAlignment="Right" >
              <Button Content="Minimze" Command="{Binding HidePanelCommand}"/>
            </StackPanel>
          </Grid>
        </Border>

        <ContentPresenter Grid.Row="1" Margin="2" Content="{Binding PanelViewModel}" VerticalAlignment="Top"/>
      </Grid>
    </Border>
  </Grid>
</Grid>

视图模型如下:

public class TestTabViewModel : ObservableObject
{
    #region private attributes

    #endregion

    public TestTabViewModel(string panelName, object panelViewModel, object mainViewModel)
    {
        IsPanelHidden = true;
        PanelTitle = panelName;
        PanelViewModel = panelViewModel;
        MainViewModel = mainViewModel;
        ShowPanelCommand = new DelegateCommand(() =>ManagePanelVisibility(true));
        HidePanelCommand = new DelegateCommand(() => ManagePanelVisibility(false));
    }

    #region properties


    public string PanelTitle { get; private set; }

    public bool IsPanelHidden { get; private set; }

    public object PanelViewModel { get; private set; }

    public object MainViewModel { get; private set; }

    public DelegateCommand ShowPanelCommand { get; private set; }

    public DelegateCommand HidePanelCommand { get; private set; }

    #endregion

    #region private methods

    private void ManagePanelVisibility(bool visible)
    {
        IsPanelHidden = !visible;
        RaisePropertyChanged(() => IsPanelHidden);
    }

    #endregion
}

所以很好,这个系统工作得很好我还添加了一些pin命令,但我从这里删除它们使它“简单”。

主视图模型持有制表符控件时出现问题。在这种情况下,如果我选择一个选项卡并“打开”面板,则选择的选项卡将“更改”。事实上,它并没有改变,只是我显示另一个不与前一个同步的contentControl。我猜即使背后的viewmodel是。

,视图实例也不一样

那么如何在视图中共享视图实例(或者让选择过程同步)?我的第一个客人是使用datatemplate(如示例中所示),但它没有解决我的问题。

顺便说一句,我知道一些第三方处理面板对接销......(例如avalon)但我找到的所有东西对于我的简单需求来说真的太多了。

感谢您的帮助

2 个答案:

答案 0 :(得分:1)

您最好的选择可能是用一个ContentControl替换两个网格,然后在按钮单击或触发器中切换Template。这样您的实际内容(TabControl)将相同,但用于显示内容的模板将更改

这是一个简单的例子:

<Window.Resources>
    <ControlTemplate x:Key="Grid1Template" TargetType="{x:Type ContentControl}">
        <DockPanel>
            <Grid Background="CornflowerBlue" Width="100" DockPanel.Dock="Left" />
            <ContentPresenter Content="{TemplateBinding Content}" />
        </DockPanel>
    </ControlTemplate>

    <ControlTemplate x:Key="Grid2Template" TargetType="{x:Type ContentControl}">
        <DockPanel>
            <Grid Background="CornflowerBlue" Width="100" DockPanel.Dock="Right" />
            <ContentPresenter Content="{TemplateBinding Content}" />
        </DockPanel>
    </ControlTemplate>
</Window.Resources>

<DockPanel>
    <ToggleButton x:Name="btnToggle" Content="Toggle View" DockPanel.Dock="Top" />
    <ContentControl>
        <ContentControl.Style>
            <Style TargetType="{x:Type ContentControl}">
            <Setter Property="Template" Value="{StaticResource Grid1Template}" />
            <Style.Triggers>
                    <DataTrigger Binding="{Binding ElementName=btnToggle, Path=IsChecked}" Value="True">
                        <Setter Property="Template" Value="{StaticResource Grid2Template}" />
                </DataTrigger>
            </Style.Triggers>
            </Style>
        </ContentControl.Style>

        <TabControl>
            <TabItem Header="Tab1" />
            <TabItem Header="Tab2" />
            <TabItem Header="Tab3" />
        </TabControl>
    </ContentControl>

</DockPanel>

答案 1 :(得分:0)

我不知道我能得到你想要的东西,但我认为你可以做到以下几点。

我假设你想要一些“MainViewmodeldata”作为你的tabcontrol。 所以我首先要为此创建一个数据模板。

<UserControl.Resources>
 <DataTemplate DataType="{x:Type MainViewmodeldata}">
  <TabControl>
   <TabItem Header="Tab1">
    <TextBlock Grid.Column="1" Text="Tab1Content"/>
    </TabItem>
   <TabItem Header="Tab2">
    <TextBlock Grid.Column="1" Text="Tab2Content"/>
   </TabItem>
  </TabControl>
 </DataTemplate>
</UserControl.Resources>

现在我只是将我的mainviewmodeldata绑定到contentcontrol并让wpf为你渲染它。我真的不知道你是否还需要这两个网格,因为我不知道你想要达到的目标。

 <Grid x:Name="Grid1" Visibility="{Binding IsPanelHidden, Converter={StaticResource bool2VisibilityConverter}}">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="Auto"/>
  </Grid.ColumnDefinitions>

  <ContentControl Content="{Binding MainViewmodelData}" />

  <StackPanel  Grid.Column="1">
    <Button x:Name="Button1" Content="Switch look" Command="{Binding ShowPanelCommand}"/>
    <TextBlock Text="Look1"/>
  </StackPanel>
 </Grid>

<Grid x:Name="Grid2" Visibility="{Binding IsPanelHidden, Converter={StaticResource revertBool2VisibilityConverter}}">
  <ContentControl Content="{Binding MainViewmodelData}" />
  <StackPanel HorizontalAlignment="Right">
    <Button x:Name="Button2" Content="Switch look" Command="{Binding HidePanelCommand}"/>
    <TextBlock Text="Look2"/>
  </StackPanel>
 </Grid>
</Grid>