1

私のシナリオでは、MainView + MainViewModel、UserControl1 + UserControl 2 があります。MainView には、Button_ShowUserControl1 + Button_ShowUserControl2 というラベルの付いた 2 つのボタンがあります。MainView の下部には、すべての UserControl を取得する「ContentGrid」があります。

私の目標:

Button_ShowUserControl1 がクリックされた場合、 UserControl1Visibleであり、UserControl2 またはその他の UserControl はCollapsedに設定する必要があります。同じことが Button_ShowUserControl2 にも有効です。

私の問題:

1.) アプリケーションの開始時に UserControls がロードされるため、それらをすべて 1 つの「ContentGrid」にまとめるにはどうすればよいですか? それは実際には不可能です...では、他のユーザーコントロールが同じ場所にあるときに、他のユーザーコントロールを表示するにはどうすればよいですか/「ContentGrid」が折りたたまれているだけですか?

2.) 1.) は不可能のようですが、アプリケーションの開始時にすべての UserControls をインスタンス化し、それぞれのボタンがクリックされたときに表示/折りたたみのみにする方法を教えてください。

3.) UserControl にはプロパティ Visibility = Visible/Hidden/Collapsed があるため、Collapsed のような値を返す ViewModel のプロパティにバインドするにはどうすればよいですか? Visibility = false/true のようなブール値しか取得できませんでしたか?

私のテストコード:

<Grid x:Name="LayoutRoot" Background="#FFBDF5BD" ShowGridLines="False">
    <Grid.RowDefinitions>
        <RowDefinition Height="96*" />
        <RowDefinition Height="289*" />
    </Grid.RowDefinitions>      
    <Grid HorizontalAlignment="Stretch" Name="MenuGrid" VerticalAlignment="Stretch" Background="#FFCECEFF">
        <StackPanel Name="stackPanel1" Background="#FFEDFF00" Orientation="Horizontal">
            <Button Content="User Data 1" Height="35" Name="button1" Command="{Binding  Path=ShowUserControl1Command}" Width="150" Margin="100,0,0,0" />
            <Button Content="User Data 2" Height="35" Name="button2" Width="150" Margin="100,0,0,0" />
        </StackPanel>
    </Grid>
    <Grid Grid.Row="1" HorizontalAlignment="Stretch" Name="ContentGrid" VerticalAlignment="Stretch" Background="#FFB15454" />
</Grid>

<UserControl x:Class="SwapUserControls.MVVM.UserControl2"
         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:vm="clr-namespace:SwapUserControls.MVVM.ViewModel"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" Visibility="{Binding IsUserControl1Collapsed, Path=Value}">

<UserControl.Resources>
    <vm:MainViewModel x:Key="MainViewModelID" />
</UserControl.Resources>

<UserControl.DataContext>
    <Binding Source="{StaticResource MainViewModelID}" />
</UserControl.DataContext>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="228*" />
        <RowDefinition Height="72*" />
    </Grid.RowDefinitions>
    <Button Content="UserControl2" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="112,27,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
    <DataGrid HorizontalAlignment="Stretch" Name="dataGrid1" VerticalAlignment="Stretch" Background="#FFC046F8" />
</Grid>

public class MainViewModel : ViewModelBase
{
    RelayCommand _ShowUserControl1Command;
    private bool _IsUserControl1Collapsed;

    public RelayCommand ShowUserControl1Command
    {
        get
        {
            if (_ShowUserControl1Command == null)
            {
                _ShowUserControl1Command = new RelayCommand( () => ShowUserControl1() );                       
            }
            return _ShowUserControl1Command;
        }
    }

    public void ShowUserControl1()
    {
        _IsUserControl1Collapsed = true;
    }

    public bool IsUserControl1Collapsed 
    {          
        get
        {
            return _IsUserControl1Collapsed;
        }  
    }        
}

はい、コードが間違っているので、ここで質問します:)

4

1 に答える 1

9

このコードには 2 つの問題があります。

1)ユーザーコントロールの可視性を直接設定することはできません...コンテナに設定する必要があります:

<Grid Visibility="Collapsed">
    <myControls:MyUserControl />
</Grid>

2) 可視性はブール値ではなく、列挙型です。そのため、コンバーターを使用してブール値から可視性に変換する必要があります。観察:

<Window ...>
<Window.Resources>
     <BooleanToVisibilityConverter x:Key="BoolToVis" />
</Window.Resources>

<Grid Visibility="{Binding ShouldShowUsercontrol1, Converter={StaticResource BoolToVis}}">
     <myControls:MyUserControl />
</Grid>
</Window>

それだけです。お役に立てれば。

これが機能する能力に影響を与える可能性のある手がかりを残している他のものがあります。たとえば、最大のコンテナ要素を表示していません... StackPanel ですべてをラップしていますか? たとえば、すべてをグリッドでラップしている場合、コントロールはすべてをレイヤーでオーバーレイします。

私が提案するこれらの変更を試してみてください...それはあなたに近づくはずです。


編集:データテンプレートを使用した別のアイデア

他にできることは、表示および非表示にするこれらのビューごとに一意の ViewModel があることを確認することです。

public class MyFirstViewModel : ViewModel
{

}

public class MySecondViewModel : ViewModel
{

}

次に、「親」または「メイン」ViewModel から、必要なビューを表示または非表示にします。これは、ビューモデルのコレクションにそれらを含めることによって行います。

public MyMainViewModel : ViewModel
{
     public ObservableCollection<ViewModel> ViewsToShow
     {
          ...
     }

     public void ShowFirstViewModel()
     {
          ViewsToShow.Add(new MyFirstViewModel());
     }
}

ビューですべてを結び付けるには、これらの型をユーザー コントロールでデータ テンプレート化します (ただし、必要でない限り、これらのビューがインスタンス化されることはありません。

<Window ...>
     <Window.Resources>
          <DataTemplate DataType="{x:Type myViewModels:MyFirstViewModel}">
               <myViews:MyFirstView />
          </DataTemplate>

          <DataTemplate DataType="{x:Type myViewModels:MySecondViewModel}">
               <myViews:MySecondView />
          </DataTemplate>
     </Window.Resources>

     <ItemsControl ItemsSource="{Binding ViewsToShow}" />

</Window>

また、「ViewsToShow」に配置したViewModelについては、ビューは自動的にそれとテンプレートを適切なビューに表示します。繰り返しますが、必要になる前にインスタンス化する必要はありません。

これはおそらく、単一のものすべてをビューに配置して可視性を設定するよりも少しきれいですが、すべてのビューに固有のビュー モデル タイプがあるかどうかに依存するため、そうではない場合があります。


DataTemplated アプローチを使用すると、状態を保存するという問題が発生します。ここでの解決策は、ViewModel をコントロールの状態として処理し、それに応じて ViewModel と View の両方を設計することです。以下は、DataTemplating を使用してビューを交換できるようにする例ですが、前後に切り替えると状態が保存されます。

データ テンプレートが定義されている 2 つのビューモデルを使用して、前のセクションのセットアップがあるとします。MainViewModel を少し変更しましょう。

public MyMainViewModel : ViewModel
{
     public RelayCommand SwapViewsCommand
     {
          ...
     }

     public ViewModel View
     {
          ...
     }
     private ViewModel _hiddenView;
     public MyMainViewModel()
     {
          View = new MyFirstViewModel();
          _hiddenView = new MySecondViewModel();
          SwapViewsCommand = new RelayCommand(SwapViewModels);
     }

     public void SwapViewModels()
     {
          var hidden = _hiddenView;
          _hiddenView = View;
          View = hidden;
     }
}

そして、メイン ビューにいくつかの変更を加えます。簡潔にするために、DataTemplates は省略しました。

<Window ...>
     <!-- DataTemplates Here -->
     <Button Command="{Binding SwapViewsCommand}">Swap!</Button>
     <ContentControl Content="{Binding View}" />
</Window>

それでおしまい。ここでの秘密は、元のビュー モデルへの参照を保存していることです。このように、ビューモデルに文字列プロパティがあり、DataTemplated ユーザー コントロールに関連付けられたテキスト ボックスがあり、双方向バインディングがあるとします。状態は基本的に保存されます。

于 2010-01-20T16:26:28.147 に答える