Reputation: 144
I have a tabControl in my MainWindow and a working LeftWindowCommand
<Controls:MetroWindow.LeftWindowCommands>
<Controls:WindowCommands >
<Button x:FieldModifier="public" x:Name="btnOpenBanMenu" Click="btnOpenBanMenu_Click">
<StackPanel Orientation="Horizontal">
<Rectangle Width="20"
Height="20"
Fill="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{StaticResource bans}" />
</Rectangle.OpacityMask>
</Rectangle>
<TextBlock Margin="4 0 0 0"
VerticalAlignment="Center"
Text="Bans"/>
</StackPanel>
</Button>
</Controls:WindowCommands>
</Controls:MetroWindow.LeftWindowCommands>
It's all fine. But now i want to use the LeftWindowCommand as a "Sub-Menu-Bar", so if you change the selected Tab, the LeftWindowCommands-Bar should also change there items and the actions behind the buttons. I've played around with the visibility, but that's not what i want.
For better understanding:
You see the items "Giveaway, Losung, Songrequest". These items are inside my TabControl.
And now i want to change the "Sub Menu"-Items (described in the picture) when i select a different tab then giveaway.
Can someone guide me, how to do that?
EDIT2: Finally it works with MVVM, but i still dont know, how to bind the LeftWindowCommands.
MainModel:
class MainModel
{
public string Header { get; set; }
public MahApps.Metro.Controls.MetroContentControl Content { get; set; }
public MahApps.Metro.Controls.WindowCommands LeftWindowCommands { get; set; }
}
MainViewModel:
class MainViewModel : BaseViewModel
{
private ObservableCollection<Model.MainModel> _tabItems;
public ObservableCollection<Model.MainModel> tabItems
{
get { return _tabItems; }
set
{
_tabItems = value;
OnPropertyChanged("tabItems");
}
}
public MainViewModel()
{
_tabItems = new ObservableCollection<Model.MainModel>()
{
new Model.MainModel
{
Header = "Giveaway",
Content = new Controls.ucGiveaway(),
LeftWindowCommands = LeftWindowCommandsGiveaway()
},
... etc
};
}
private MahApps.Metro.Controls.WindowCommands LeftWindowCommandsGiveaway()
{
MahApps.Metro.Controls.WindowCommands command = new MahApps.Metro.Controls.WindowCommands();
command.Items.Add(
new Button { Content = "MyButton #1", Foreground = Brushes.Red });
return command;
}
}
DataContext:
<Controls:MetroWindow.DataContext>
<ViewModels:MainViewModel/>
</Controls:MetroWindow.DataContext>
TabControl:
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Header}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<Controls:MetroContentControl
Content="{Binding Content}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
This works. The designer shows all tabs & content. How can i bind the WindowCommands? I want something like:
<Controls:MetroWindow.LeftWindowCommands>
<Controls:WindowCommands ItemsSource="{Binding LeftWindowCommands}">
</Controls:WindowCommands>
</Controls:MetroWindow.LeftWindowCommands>
Furthermore i want to be able to add more than one button in my MainViewModel. Something like:
private MahApps.Metro.Controls.WindowCommands LeftWindowCommandsGiveaway()
{
MahApps.Metro.Controls.WindowCommands command = new MahApps.Metro.Controls.WindowCommands();
command.Items.Add(
new Button { Content = "MyButton #1", Foreground = Brushes.Red });
command.Items.Add(
new Button { Content = "MyButton #2", Foreground = Brushes.Red });
return command;
}
Upvotes: 1
Views: 1446
Reputation: 85
I think the problem is you binds WindowCommands.ItemSource to a WindowCommands object instead of a collection of controlelements (like button, textblock)
here is my solution:
MainWindow.xaml
<mah:MetroWindow x:Class="WpfApp1.MainWindow"
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:WpfApp1"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<mah:MetroWindow.LeftWindowCommands>
<mah:WindowCommands ItemsSource="{Binding Buttons}">
</mah:WindowCommands>
</mah:MetroWindow.LeftWindowCommands>
<TabControl x:Name="MainTab" ItemsSource="{Binding TabItems}">
</TabControl>
</mah:MetroWindow>
MainModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Media;
namespace WpfApp1
{
public class MainModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<TabCustomItem> mTabItems;
private ObservableCollection<Button> mButtons;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ObservableCollection<TabCustomItem> TabItems
{
get { return mTabItems; }
set
{
mTabItems = value;
OnPropertyChanged("TabItems");
}
}
public ObservableCollection<Button> Buttons
{
get { return mButtons; }
set
{
mButtons = value;
OnPropertyChanged("Buttons");
}
}
public MainModel()
{
ObservableCollection<Button> Buttons1 = new ObservableCollection<Button>()
{
new Button()
{
Content = "Press Tab #1"
}
};
ObservableCollection<Button> Buttons2 = new ObservableCollection<Button>()
{
new Button()
{
Content = "Press Tab #2"
}
};
ObservableCollection<Button> Buttons3 = new ObservableCollection<Button>()
{
new Button()
{
Content = "Press Tab #3"
}
};
Buttons = Buttons1;
mTabItems = new ObservableCollection<TabCustomItem>
{
new TabCustomItem()
{
Header = "Tab #1",
ToolItemsSource = Buttons1
},
new TabCustomItem()
{
Header = "Tab #2",
ToolItemsSource = Buttons2
},
new TabCustomItem()
{
Header = "Tab #3",
ToolItemsSource = Buttons3
}
};
}
}
}
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using MahApps.Metro.Controls;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : MetroWindow
{
private MainModel mMainModel;
public MainWindow()
{
InitializeComponent();
this.MainTab.SelectionChanged += MainTab_SelectionChanged;
mMainModel = new MainModel();
DataContext = mMainModel;
}
private void MainTab_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
TabCustomItem ti = (sender as TabControl).SelectedItem as TabCustomItem;
mMainModel.Buttons = ti.ToolItemsSource;
}
}
}
TabCustomItem.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using MahApps.Metro.Controls;
namespace WpfApp1
{
public class TabCustomItem : TabItem
{
public static readonly DependencyProperty ToolItemsSourceProperty = DependencyProperty.Register(nameof(ToolItemsSource), typeof(ObservableCollection<Button>),
typeof(TabCustomItem), new PropertyMetadata(null));
public ObservableCollection<Button> ToolItemsSource
{
get { return (ObservableCollection<Button>)GetValue(ToolItemsSourceProperty); }
set { SetValue(ToolItemsSourceProperty, value); }
}
}
}
you can add whatever control to windowcommands by generating more general control collections. I can't reference the selected tab in data binding and that's why i use event handler to assign the current control collection to the data i bind to (variable Buttons)
maybe rewriting a tabcontrol and add a binding variable will make it simple (reference that variable in data binding)
Upvotes: 0
Reputation: 1454
Ideally, you would use Bindings, but since you are using code-behind, here's a simple solution (it is up to you if you want to adapt it to some patter like MVVM):
Basically what this code does is:
There's a List
of UIElements
containing all the sub-menus (they can be anything, from a simple Button
to a StackPanel
full of elements).
Inside the WindowCommands
there's a TransitioningContentControl
which will be responsible for containing the sub-menu.
Everytime the selected tab changes, I load the n position of the List
to the TransitioningContentControl
(n is the selected index of the TabControl
).
And here's the code I've used for the example, so you can adapt it:
public partial class MainWindow : MetroWindow
{
public List<UIElement> LeftWindowCommands { get; private set; }
public MainWindow()
{
InitializeComponent();
LeftWindowCommands = new List<UIElement>();
var StackPanelForTab1 = new StackPanel() { Orientation = Orientation.Horizontal };
var StackPanelForTab2 = new StackPanel() { Orientation = Orientation.Horizontal };
var StackPanelForTab3 = new StackPanel() { Orientation = Orientation.Horizontal };
// You can add as many children as you want
StackPanelForTab1.Children.Add(new Button { Content = "MyButton #1", Foreground = Brushes.Red });
StackPanelForTab2.Children.Add(new Button { Content = "MyButton #2", Foreground = Brushes.Black });
StackPanelForTab3.Children.Add(new Button { Content = "MyButton #3", Foreground = Brushes.Blue });
// MUST add items in the right order on the list
// MUST have the sabe amount of tabs on the TabControl and items on the list
LeftWindowCommands.Add(StackPanelForTab1);
LeftWindowCommands.Add(StackPanelForTab2);
LeftWindowCommands.Add(StackPanelForTab3);
}
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.Source is TabControl)
{
MyContentControl.Content = LeftWindowCommands[MyTabControl.SelectedIndex];
}
}
}
<Controls:MetroWindow x:Class="WpfTests.MainWindow"
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:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:local="clr-namespace:WpfTests"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Controls:MetroWindow.LeftWindowCommands>
<Controls:WindowCommands>
<Controls:TransitioningContentControl x:Name="MyContentControl" />
</Controls:WindowCommands>
</Controls:MetroWindow.LeftWindowCommands>
<TabControl SelectionChanged="TabControl_SelectionChanged" x:Name="MyTabControl" >
<TabItem Header="Tab #1">
<Label>#1</Label>
</TabItem>
<TabItem Header="Tab #2">
<Label>#2</Label>
</TabItem>
<TabItem Header="Tab #3">
<Label>#3</Label>
</TabItem>
</TabControl>
</Controls:MetroWindow>
You'll need this:
using MahApps.Metro.Controls;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
If you try to adapt it to MVVM and have any troubles I'm here to help.
Upvotes: 2