0

私はWPFとMVVMの両方が初めてです。MVVMパートターンでメニューを動的に作成する良い方法を探しましたが、自分の好みに合うものが見つからないので、独自のソリューションを展開しました。動作しますが、何らかの理由で、メニューの前景色 (テキスト) の色が正しくないことがあります。

下の画像のリンクを追加しました。

http://img220.imageshack.us/img220/1912/badmenu.jpg (リンク切れ)

一番下のサブメニューは前景が白で正しく表示されますが、その親メニューの前景は黒に変わり、ほとんど読むことができません。メニューをハードコーディングした場合、親の前景色は白になります。親の上にマウスを移動すると、そのテキストは白に戻り、サブメニューは黒になります。

さらに、マウスを親から遠ざけると、そのブール値のプロパティはすべてIsHighlighted, IsSubmenuOpen, etc...false になります。これは、true のままであるべきだと思うので驚くべきことです。最終結果は、スタイル トリガーでこれを解決できなかったということです。

これが私の XAML です。

<Window.Resources>
  <DataTemplate DataType="{x:Type src:ParentMenu}" >
    <Menu >
      <MenuItem Header="{Binding MenuName}" ItemsSource="{Binding ChildMenuItems}" />
    </Menu>
  </DataTemplate>

  <HierarchicalDataTemplate DataType="{x:Type src:ChildMenu}" 
                          ItemsSource="{Binding ChildMenuItems}" >
    <MenuItem Header="{Binding MenuName}" Command="{Binding Path=Command}" />
  </HierarchicalDataTemplate>

' StackOverflow が Window.Resources の終了タグをマスキングしています

<DockPanel>
   <Menu DockPanel.Dock="Top" ItemsSource="{Binding Menus}" />

  <Grid>
       <!-- Add additional content here -->
  </Grid>
</DockPanel>

ParentMenuとの両方が、実際にすべてのメニューを保持し、コレクションChildMenuを通じてサブメニューを公開する共通クラスから継承します。オブジェクトのリストです。オブジェクトのリストを公開します。ChildMenuItemsChildMenuItemsChildMenuViewModelsParentMenu

ここで私が望むことを達成するためのより良い方法がおそらくあります。次に例を示します。

img132.imageshack.us/img132/4160/bettermenu.jpg (リンク切れ)

私が間違っていること、および/または表示の問題を修正する方法について何か提案はありますか?

4

2 に答える 2

1

問題は、VM が自動的に MenuItem にラップされるため、基本的に MenuItem が MenuItem のヘッダーとしてネストされていることです。

これを回避するには、MenuItem を DataType として使用して VM に DataBinds するスタイル (および ItemContainerStyle を介してそれを指す) (Name から Header、DelegateCommands から Command など) を使用します。

これを行う方法の例を以下に示します。ItemContainerStyle を優先して HierarchicalDataTemplate を削除したことに注意してください。また、MainViewModel の DataTemplate を自由に定義することもできました。これは、それがどのようにデータ バインドされているかが明確ではなかったためです。

<Window.Resources>
    <DataTemplate DataType="{x:Type src:MainViewModel}">
        <ItemsControl ItemsSource="{Binding Menus}"></ItemsControl>
    </DataTemplate>
    <DataTemplate DataType="{x:Type src:ParentMenu}" >
        <Menu>
            <MenuItem Header="{Binding Name}" 
        ItemsSource="{Binding ChildMenuItems}" ItemContainerStyle="{DynamicResource ChildMenuItemStyle}" />
        </Menu>
    </DataTemplate>
    <Style x:Key="ChildMenuItemStyle" TargetType="MenuItem">
        <Setter Property="Header" Value="{Binding Name}"></Setter>
        <Setter Property="ItemsSource" Value="{Binding ChildMenuItems}"></Setter>
    </Style>
</Window.Resources>

また、わかりやすくするために Command バインディングの一部を省略しましたが、必要に応じて再度追加できます。

于 2009-06-18T18:32:16.657 に答える
0

リクエストに応じて、ここに私の ViewModels があります。

ViewModelBase は studio によって作成された標準のものです。MainVieModel には、実験に使用していたテスト メニューを作成するのに十分なものが含まれています。

基本的に、幅広いクライアントに販売する一連のアプリで使用できる親子メニュー クラスの作成に取り組んでいます。私は、各顧客が自分のニーズとライセンスを購入したモジュールに基づいて、カスタマイズ可能なメニューのコレクションを持てるようにしたいと考えています.

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}   

パブリック クラス MainViewModel : ViewModelBase

{

    public MainViewModel()  {   MakeMenus();    }

    private void MakeMenus()
    {
        // Makes some dummy menus to test with.
        Menus = new ObservableCollection<MyMenuItem>();
        ParentMenu parent;
        ChildMenu child;

        parent = new ParentMenu("First Level");
        Menus.Add(parent);
        child = new ChildMenu(parent, "second level");
        parent.ChildMenuItems.Add(child);
        ChildMenu child2 = new ChildMenu(child, "third level");
        child2.MenuCommand = new DelegateCommand(CommandTest,
                                                   CommandCanExecute_First);
        child.ChildMenuItems.Add(child2);

        child = new ChildMenu(parent, "second level 2");
        parent.ChildMenuItems.Add(child);
        child2 = new ChildMenu(child, "third level 2");
        child2.MenuCommand = new DelegateCommand(CommandTest, 
                                       CommandCanExecute_Second);
        child.ChildMenuItems.Add(child2);

        parent = new ParentMenu("Another First");
        parent.ChildMenuItems.Add(new ChildMenu(parent, "Another Second"));
        Menus.Add(parent);
        OnPropertyChanged("Menus");
    }

    private bool ExecuteToggle { get; set; }
    private void CommandTest()  {   ExecuteToggle = !ExecuteToggle; } 
    public ObservableCollection<MyMenuItem> Menus  {  get; private set;}
    public bool CommandCanExecute_First()   {   return ExecuteToggle;   }
    public bool CommandCanExecute_Second() { return !ExecuteToggle;     }
}
于 2009-06-18T14:21:26.467 に答える