MahApps:Metro SplitButton Control Template - wpf

Default SplitButton works ok, but when I try to work with it's control template issues arise.
If I try to get Control Template with reflection (with ConstructorInfo) I get empty Control Template for SplitButton. If I try to 'Edit Template copy' in XAML Designer, I get copy which does not work (like ItemsSource does not bind to elements in ListBox of SplitButton as it is always empty).
My version of MahApps Metro is 1.4.3.0
Here is how I try to get Control Template of SplitButton:
MahApps.Metro.Controls.SplitButton ctl = sender as MahApps.Metro.Controls.SplitButton;
Type type = ctl.GetType();
if (type == null)
return;
// Instantiate the type.
ConstructorInfo info = type.GetConstructor(System.Type.EmptyTypes);
Control control = (Control)info.Invoke(null);
// Get the template.
ControlTemplate template = control.Template;
// Get the XAML for the template.
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
StringBuilder sb = new StringBuilder();
XmlWriter writer = XmlWriter.Create(sb, settings);
XamlWriter.Save(template, writer);

The default ControlTemplate is available on GitHub: https://github.com/MahApps/MahApps.Metro/blob/336f7dfc4bda2d0eba8aa270737ca3c11d45128c/src/MahApps.Metro/MahApps.Metro/Themes/SplitButton.xaml
MahApps.Metro is open source so you can download the source code if you want to.

After updating MahApps Metro to 1.5.0 SplitButton works fine with provided Control Templates...

Related

How to apply styles in a resource dictionary that is programmatically added to the App.Current.Resources.MergedDictionaries collection?

I am working with a very large Silverlight 5 application that needs to implement theming. Unfortunately I can't use the C1 (Component One) or Silverlight Toolkit theme mechanisms due to the enormity of xaml and code changes I would have to implement. I am forced to do something a bit out of the box.
As a starting point I created a demo project by referencing a post on Stack Overflow Using Mef to Import a WPF DataTemplate written by #Scott Whitlock. The post described how to dynamically load a Silverlight/WPF resource dictionary and add it to the App.Current.Resources.MergedDictionaries collection within the Silverlight/WPF application.
I created 4 projects. The first being the Silverlight 5 application itself, the second, third, and forth are silverlight class libraries for defining all the theme particulars. Each class library has an entry point which is a derived type of ResourceDictionary.
On AppStart event, the application loads the default theme class library, which is essentially a blank slate with all default styles defined in Silverlight. By loading I mean the the DefaultTheme resource dictionary defined within the class library is added to the App.Current.Resources.MergedDictionaries collection.
When the user selects another theme from a combo box within the app, the code removes the existing default theme and adds the blue or red, or whatever other theme's entry point resource dictionary to the App.Current.Resources.MergedDictionaries collection.
However, even though no errors have been thrown when this action occurs, the styles themselves are never re-applied. I have verified that each theme has the same style keys across the board.
Any ideas on how to force the App.Current.RootVisual re-apply the styles from the newly added resource dictionary after a "theme switch" ?
Thanks,
Try searching for the current ResourceDictionary first and removing it before adding the new ResourceDictionary.
string themeName = "White";
string oldThemeName = "Black";
string oldResourcePathString = String.Format("/Library.Name;component/Themes/{0}Theme.xaml", oldThemeName);
StreamResourceInfo sriOldTheme = Application.GetResourceStream(new Uri(oldResourcePathString, UriKind.Relative));
if (sriOldTheme != null)
{
StreamReader sr = new StreamReader(sriOldTheme.Stream);
object resourceObject = XamlReader.Load(sr.ReadToEnd());
ResourceDictionary resource = resourceObject as ResourceDictionary;
if (resource != null)
{
Application.Current.Resources.MergedDictionaries.Remove(resource);
}
}
string resourcePathString = String.Format("/Library.Name;component/Themes/{0}Theme.xaml", themeName);
StreamResourceInfo sriTheme = Application.GetResourceStream(new Uri(resourcePathString, UriKind.Relative));
if (sriTheme != null)
{
StreamReader sr = new StreamReader(sriTheme.Stream);
object resourceObject = XamlReader.Load(sr.ReadToEnd());
ResourceDictionary resource = resourceObject as ResourceDictionary;
if (resource != null)
{
Application.Current.Resources.MergedDictionaries.Add(resource);
}
}
I never tested the code, so check for typos, but this should work whether you set the ResourceDictionary in App.xaml or programatically from MainPage.xaml.cs

TextBox inside a listview cell

I have a listview that I would like to add a textbox inside each gridview column cell so I can type data into it and then fetch that data.
I'm creating a datatemplate and passing it to a cell template for the GridViewColumn but when I look at the listview I can't add anything to the cell. It doesn't look like the textbox was even created.
GridViewColumn conceptColumn = new GridViewColumn();
conceptColumn.Header = conceptName;
conceptColumn.CellTemplate = this.GetDataTemplate();
this.TestModeler.Columns.Add(conceptColumn);
conceptColumn.DisplayMemberBinding = new Binding(conceptName);
private DataTemplate GetDataTemplate()
{
DataTemplate dt = new DataTemplate(typeof(TextBox));
FrameworkElementFactory txtElement = new FrameworkElementFactory(typeof(TextBox));
dt.VisualTree = txtElement;
Binding bind = new Binding();
bind.Path = new PropertyPath("Text");
bind.Mode = BindingMode.TwoWay;
txtElement.SetBinding(TextBox.TextProperty, bind);
txtElement.SetValue(TextBox.TextProperty, "test");
return dt;
}
Please take a look at the ListView Class page at MSDN where you can find a XAML example and plenty of link on how to do various things with a WPF ListView.
Of particular interest to you, please take a look at the How to: Use Templates to Style a ListView That Uses GridView page there which explains what you are trying to do (but in XAML) with examples.
MSDN should always be your first place to look as it is full of information just waiting to be read.

Default MenuItem TopLevelHeader Control Template

Where can I get the MenuItem TopLevelHeader Control Template? The MSDN link for styling menu items gives a modified template.
I need to obtain a control template that contains a default pop-up/context menu.
Manny tools are available that will serve the purpose like stylesnooper and Show Me The Template
but if you have Microsoft Expression Blend you can extract the default control template by
Draggint the control onto the design
surface
Right click the control and choose
Edit Template -> Edit Copy
When you do this, Blend will extract the base template from the control and explicitly declare it within document/application as a resource which you can then edit to your liking.
Check this for more
http://www.shafqatahmed.com/2009/01/wpf-kid-stuff-extracting-a-control-template.html
I could not get Blend or the usual tools to access that control template but you can extract it yourself with code like the following:
var controlTemplate = (ControlTemplate)FindResource(MenuItem.TopLevelHeaderTemplateKey);
var sb = new StringBuilder();
var xml = XmlWriter.Create(sb, new XmlWriterSettings { Indent = true, NewLineOnAttributes = true });
XamlWriter.Save(controlTemplate, xml);
var xaml = sb.ToString();
Debug.WriteLine(xaml);
The output is too long to include here.

Dynamic Control Template in Silverlight

I'm trying to make a button in Silverlight use a control template to change the way it looks.
I need to do this dynamically in code (not xaml markup).
The Button object has a Template property to which you can assign a ControlTemplate.
But how do you stuff UI elements into the ControlTemplate?
(In WPF, there is a VisualTree property but no such property exists in Silverlight)
I'm not sure if this helps, but just in case. To create buttons using a control template in code behind (not XAML) I've done it like this:
load the control template from an xml definition (below is a link to the source)
byte[] bytes = ReadBytesFromStream("BestBuyRemix.BL.buttontemplate.xml");
string buttonTemplate = "";
UTF8Encoding encoding = new UTF8Encoding();
buttonTemplate = encoding.GetString(bytes.ToArray(), 0, (int)bytes.Length);
create the button and add it to the visual tree (in this case a wrap panel)
string onebutton = string.Format(buttonTemplate, mnu.CatItemName, mnu.CatItemImage,
"{StaticResource buttonStyle1}",
"{StaticResource CatItemNameBlock}", "{StaticResource ThumbNailPreview}",
ictr.ToString());
ictr += 1;
Button bt = (Button)XamlReader.Load(onebutton);
bt.Tag = mnu.CatItemPageUri;
bt.Click += new RoutedEventHandler(bt_Click);
Wrappable.Children.Add(bt);
I wrote a post on my blog about the Best Buy Remix API which uses this to build a product list in the details page. It has a link to the Silverlight source. In case you're interested.
blog post link

WPF Tooltip binding not updating

Good afternoon all,
I have to work with a legacy Winforms application but I'd like to start migrating it to WPF. It doesn't have a tooltip control now so I'd like to use a WPF tooltip object.
I create a single global instance of a tooltip object. I've bound the controls within it and my application sets the datacontext of the tooltip. I can manually show and hide the tooltip just fine. The first time I hover over an object it picks up the bound data perfectly and works great. When I move over another control the tooltip datacontext is changed but the displayed data is never reloaded.
I tried implementing a property changed event and use the INotifyPropertyChanged interface in the object I bind to. It appears the wpf tooltip is not listening to the event.
I tried setting the binding mode to Oneway (it's a display only tooltip).
The tooltip is created programmatically:
// build the tooltip window.
System.Windows.Controls.Image img = new System.Windows.Controls.Image();
img.Width = 50;
img.Height = 60;
// bind the image
System.Windows.Data.Binding imageBinding = new System.Windows.Data.Binding("PatientImage.Data");
imageBinding.Mode = System.Windows.Data.BindingMode.OneWay;
imageBinding.Source = bed;
img.SetBinding(System.Windows.Controls.Image.SourceProperty, imageBinding);
// wrap image in a border
System.Windows.Controls.Border brdr = new System.Windows.Controls.Border();
brdr.BorderBrush = System.Windows.Media.Brushes.Blue;
brdr.Margin = new System.Windows.Thickness(6);
brdr.Child = img;
System.Windows.Controls.WrapPanel wp = new System.Windows.Controls.WrapPanel();
System.Windows.Controls.TextBlock tb = new System.Windows.Controls.TextBlock();
tb.Background = System.Windows.Media.Brushes.LightBlue;
tb.Foreground = System.Windows.Media.Brushes.Blue;
// bind the text block
System.Windows.Data.Binding textBlockBinding = new System.Windows.Data.Binding("TooltipText");
textBlockBinding.Mode = System.Windows.Data.BindingMode.OneWay;
textBlockBinding.Source = bed;
tb.SetBinding(System.Windows.Controls.TextBlock.TextProperty, textBlockBinding);
wp.Children.Add(brdr);
wp.Children.Add(tb);
bedTooltip = new System.Windows.Controls.ToolTip();
bedTooltip.Content = wp;
Any idea why this doesn't work? Maybe I need to use a tooltip object for each control instead of a single global one as a workaround?
The bindings specify a Source, because of that they no longer "care" about the DataContext and hence the bindings do not update if anything other than the property itself on the source-object changes.

Resources