How to get a WPF Toolbar to bind to a collection in my VM without using expander
I have a WPF window that has a ToolBar
. I have a collection of objects in my VM that I'm binding to. They appear as buttons but they always get pushed to the expanded drop down part of the ToolBar
. How do I make those buttons appear in the standard part of the ToolBar
?
I have the following XAML:
<ToolBarTray Grid.Row="1">
<ToolBar ItemsSource="{Binding Path=MyList}" >
<ToolBar.ItemTemplate>
<DataTemplate >
<Button ToolTip="{Binding ButtonName}"
Command="{Binding Path=ButtonCommand}" >
<Button.Content>
<Image Width="32" Height="32" Source="{Binding ImageSource}"/>
</Button.Content>
</Button>
</DataTemplate>
</ToolBar.ItemTemplate>
</ToolBar>
</ToolBarTray>
I have the following C#:
public List<MyClass> MyList
{
get
{
return new List<MyClass>
{
new MyClass{ButtonName="Button1",ImageSource=@"C:\Projects\WpfApplication2\WpfApplication2\Employee.pn开发者_JAVA百科g"},
new MyClass{ButtonName="Button2",ImageSource=@"C:\Projects\WpfApplication2\WpfApplication2\Employee.png"},
new MyClass{ButtonName="Button3",ImageSource=@"C:\Projects\WpfApplication2\WpfApplication2\Employee.png"},
new MyClass{ButtonName="Button4",ImageSource=@"C:\Projects\WpfApplication2\WpfApplication2\Employee.png"},
};
}
}
This is the visual result:
There is a bug in the toolbar, if you re-size the window, the problem goes away.
The solution is using another control, like:
public class WorkaroundToolBar : ToolBar
{
private delegate void IvalidateMeasureJob();
public override void OnApplyTemplate()
{
Dispatcher.BeginInvoke(new IvalidateMeasureJob(InvalidateMeasure),
DispatcherPriority.Background, null);
base.OnApplyTemplate();
}
}
Check out this thread for more info
You can also set the height of the toolbar in the xaml to a reasonable value which has worked for me.
To add to Eduardo's, I had to slightly tweak this since my item source was getting populated asynchronously, some time after the initial UI is displayed:
public class ToolBar : System.Windows.Controls.ToolBar
{
public override void OnApplyTemplate ()
{
Dispatcher.BeginInvoke ((Action)(InvalidateMeasure), DispatcherPriority.Background, null);
base.OnApplyTemplate ();
}
protected override void OnItemsChanged (NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged (e);
Dispatcher.BeginInvoke ((Action)(InvalidateMeasure), DispatcherPriority.Background, null);
}
}
This was enough to catch all edge cases and have the overflow properly happen as needed after population of the items.
精彩评论