Silverlight5 MarkupExtension at Design Time - silverlight

I have a simple IMarkupExtension as follows:
public class HelloWorldMarkup : IMarkupExtension<string>
{
public string ProvideValue(IServiceProvider serviceProvider)
{
return "Hello World";
}
public override string ToString()
{
return "DesignTime Hello World";
}
}
and my Xaml that uses it like this..
<StackPanel>
<TextBlock Text="{my:HelloWorldMarkup}" />
<HyperlinkButton Content="{my:HelloWorldMarkup}" />
</StackPanel>
At runtime, it all works as expected.
At design time however, the Content of the hyperlink shows the design time values (from ToString), but the TextBlock's Text does not show.
If I leave it like this, my designer will whinge to me for days.. Does anyone have any suggestions on how I can have my Markups display design time data in TextBlock Text?
Many thanks,

try..
<TextBlock DataContext="{my:HelloWorldMarkup}" Text="{Binding}" />

You're halfway on the right track. There's some nice workaround to this ("by design") problem:
Use the interface IMarkupExtension and derive from some control with a content property ( e.g. ContentControl).
Now listen to changes to the "Parent" property (you may have to use some tricky workaround using attached properties). The event callback should then call ProvideValue on its own using a custom simple IProvideValueTarget implementation. The result of ProvideValue must then be assigned to the "Content" property. This does not affect runtime as ProvideValue will be evaluated before the control and works like a charm in design time.
I'm also thinking about installing a Binding on the target property thus reducing the base class to FrameworkElement.
Refer to https://github.com/MrCircuit/XAMLMarkupExtensions and https://github.com/MrCircuit/WPFLocalizationExtension for an example of this process.

Related

Changing WPF Decorator Child Base on a Property Value

I have a WPF control whose content completely depends on a property of its data context. For the sake of this, let's just say the control's DataContext is of type Product, which has a Status property of InStock, OutOfStock, or Discontinued.
I have individual user controls for each of those status types. I could, and have, created some kind of panel that binds the visiblity of each to Product.Status. But that created problems, since some of the user controls ended up with funky stuff because some depend on various properties being set. And in my actual application, there are many statuses, so the visualtree gets too big for my taste.
I solved the problem by creating and in my code, I check for a status change on the DataContext and set the appropriate child in a big switch statement. I would like to do this in XAML if possible. I want the child to be set on demand, so I assume I'll need to use templates. Something like this:
SwitchControl would derive from Decorator or Border, whatever.
<SwitchControl Property="Status">
<SwitchControl.Possibilities>
<Possibility Value="Discontinued">
<Possibility.Template>
<DiscontinuedView />
</Possibility.Template>
</Possibility>
<Possibility Value="InStock">
<Possibility.Template>
<InStockView />
</Possibility.Template>
</Possibility>
<SwitchControl.Possibilities />
</SwitchControl>
It would be even better if I could shorten the whole thing to:
<SwitchControl>
<Possibility Value="Discontinued">
<DiscontinuedView />
</Possibility>
<Possibility Value="InStock">
<InStockView />
</Possibility>
</SwitchControl>
Point being, only one child would exist at any given time. Anyone know of a way to get this done? I looked around in MVVM frameworks and couldn't find anything. Otherwise I'll experiment with creating a custom control myself.
You might want to take a look at the DataTemplateSelector class. This allows you to define templates based on different criteria, e.g. the type of the current DataContext. An example could look somewhat like the following:
public class MyDataTemplateSelector : DataTemplateSelector
{
public DataTemplate DiscontinuedDataTemplate { get; set; }
public DataTemplate InStockDataTemplate { get; set; }
public DataTemplate OutOfStockDataTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var product = item as Product;
switch (product.Status)
{
case Status.InStock:
return InStockDataTemplate;
case Status.Discontinued:
return DiscontinuedDataTemplate;
case Status.OutOfStock:
return OutOfStockDataTemplate;
}
// Fallback
return DiscontinuedDataTemplate;
}
}
...and use it in the following way:
<Window.Resources>
<DataTemplate x:Key="DiscontinuedDataTemplate">
<DiscontinuedView />
</DataTemplate>
<DataTemplate x:Key="InStockDataTemplate">
<InStockView />
</DataTemplate>
<DataTemplate x:Key="OutOfStockDataTemplate">
<OutOfStockView />
</DataTemplate>
<!-- DataTemplate Selector -->
<local:MyDataTemplateSelector x:Key="MyTemplateSelector"
DiscontinuedDataTemplate="{StaticResource DiscontinuedDataTemplate}"
InStockDataTemplate="{StaticResource InStockDataTemplate}"
OutOfStockDataTemplate="{StaticResource OutOfStockDataTemplate}"/>
</Window.Resources>
<ContentControl ContentTemplateSelector="{StaticResource MyTemplateSelector}" Content="{Binding Product}"/>
Thanks for the suggestion andreask. I ended up creating a control that I think solves the problem more directly. I've been working on a WPF helper library that I'll post to nuget in the future, but if you want to use it now, it's at:
https://gist.github.com/StevePotter/b17f8d4b2657a2d2610390a11fb57e03
Example XAML is included. I hope this is useful for someone!

Using commands inside control templates within resource dictionaries- good or bad?

I have defined a control template inside resource dictionary.
<Button Command="{Binding Path=DataContext.PrintCommand,
RelativeSource={RelativeSource
Mode=FindAncestor,AncestorType={x:Type UserControl}}}">
I am using relative source to get the data context and access the viewmodel.
In PrintViewModel
public ICommand PrintCommand { get; set; }
In Usercontrol, I set datacontext=PrintViewModel
Its working for me. But is it bad practice?
Since this can be consumed by user controls only due to the use of relative source ,making it conditional that a usercontrol is up the tree and defines a particular command?
would like to know some thoughts.
I can't say whether or not it is bad practice, but if I were you i would try a different approach.
If your Button is situated within the UserControl they should share DataContext. If they aren't, you could simply define a DataContext for the Button, not really the best choice either.
A second option would be to bind by using an Elementname and the Path.
Like this:
<Button Command="{Binding ElementName="UserControlsName", Path="PrintCommand}">
This requires you to give your UserControl a name e.g: <UserControl x:Name="MyUserControl"/>
and it should be in the same XAML-file.

How to bind a textblock's text through XAML using a property?

I am working on a Silverlight application, and I want to bind the simple text property of textblock through a property of string type.
What I did was:
<TextBlock Text="{Binding Name}"/>
Code behind:
public string Name{get;set;}
Name = "Testing..!";
but it will not work.
To expand on anatoliiG's answer (which will work): Data binding refers to properties on the DataContext property of the current element by default. This means that your
<TextBlock Text="{Binding Name}" />
is actually translated to
Set the value of the Text property to this.DataContext.Name
(DataContext is inherited, so if it is not explicitly set on the TextBlock it will check the parent, then the parent of the parent etc etc)
You can resolve your problem in one of two ways:
You can set the value of this.DataContext on the parent to the parent itself (as anatoliiG suggests). This means that when it looks up this.DataContext.Name it will be checking the Page itself, which is where your Name property is found.
You can change your Binding so it looks at the Page instead of Page.DataContext when it is looking up bindings. You can achieve this using the RelativeSource markup extension:
This translates to:
Find the first ancestor of the TextBlock that is of type Page, and bind to the Name property on that object
As a final note, you will also need to implement INotifyPropertyChanged on your DataContext object if you are going to ever change the value of Name.
Oh, and you should be using view models as the DataContext instead of the Page itself!
Answer to your question is: in Page_Loaded event set LayoutRoot.DataContext = this;. But it is more hack, than good practice.
You should take a look into MVVM pattern and INotifyPropertyChanged and create ViewModel which will contain this property.

How to make a WPF content conditional on some bound data?

I want to create a menu item but the displayed text depends on a property of the view model.
If the property IsPlaying is true, the MenuItem text should be "Pause", else it should be "Play".
Without this condition, the MenuItem should be something like:
<MenuItem Header="_Play" Command="{Binding Path=PlayCommand}" />
But, "Play" and "Pause" should interchange (and if possible PlayCommand should interchange with PauseCommand too, but this can be worked by having both the logic of PlayCommand and PauseCommand in PlayCommand)
The simplest way to do this is first you should bind the Header to a string Caption property in your viewmodel which returns Play or Pause based on the value of IsPlaying and implement INotifyPropertyChanged. After this, just throw change notification for Caption also when IsPlaying is changed.
Although you can use a converter, but in this case it will be an overkill.
A couple of ways to do this:
Use a Trigger. Set a Trigger on IsPlaying = True, and set the Header and Command to Pause and PauseCommand respectively.
Have two menu items, Play and Pause, and use a pair of triggers to set their Visibility according to IsPlaying. (You could also data-bind Visibility, but using triggers avoids the need to define a BooleanToInvisibilityConverter.)
The best thing for this is a converter. Your code will look something like this:
<UserControl xmlns:myConverters="MyRandomNamespace">
<UserControl.Resources>
<myConverters:MyMenuTextConverter x:Key="MyMenuTextConverter" />
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<TextBlock Text="{Binding IsPlaying, Converter={StaticResource MyMenuTextConverter }}" />
</Grid>
</UserControl>
and in the converter:
namespace MyRandomNamespace
{
public class MyMenuTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((bool) value == true)
return "Pause";
return "Play";
}
}
}
I've used a TextBlock to display the concept behind the binding, all you have to do is use the same binding syntax on the appropriate property of the MenuItem. I'm also returning literal text from the converter which is not optimal (personally i like my text converters to retrieve their values from a string resource file so that my app is culture aware), but you get the idea.
In WPF you can use a DataTrigger to change the content based on state in your viewmodel (you could even use this technique to swap out the template). Another alternative is to use the VisualStateManager (the distant cousin of datatriggers created for Silverlight's absence thereof that was then backported to WPF as well) to do a similar change from one state (IsPlaying) to the next (!IsPlaying).
I would love to give a more detailed example but it's past my bedtime. Maybe later today.

WPF Update Binding when Bound directly to DataContext w/ Converter

Normally when you want a databound control to 'update,' you use the "PropertyChanged" event to signal to the interface that the data has changed behind the scenes.
For instance, you could have a textblock that is bound to the datacontext with a property "DisplayText"
<TextBlock Text="{Binding Path=DisplayText}"/>
From here, if the DataContext raises the PropertyChanged event with PropertyName "DisplayText," then this textblock's text should update (assuming you didn't change the Mode of the binding).
However, I have a more complicated binding that uses many properties off of the datacontext to determine the final look and feel of the control. To accomplish this, I bind directly to the datacontext and use a converter. In this case I am working with an image source.
<Image Source="{Binding Converter={StaticResource ImageConverter}}"/>
As you can see, I use a {Binding} with no path to bind directly to the datacontext, and I use an ImageConverter to select the image I'm looking for. But now I have no way (that I know of) to tell that binding to update. I tried raising the propertychanged event with "." as the propertyname, which did not work.
Is this possible? Do I have to wrap up the converting logic into a property that the binding can attach to, or is there a way to tell the binding to refresh (without explicitly refreshing the binding)?
Any help would be greatly appreciated.
Thanks!
-Adam
The workaround here was to add a property to my object (to be used as the datacontext) called "Self" , which simply returned
public Object Self { get { return this; }}
Then in the binding I used this property:
<Image Source="{Binding Path=Self, Converter={StaticResource ImageConverter}}"/>
Then when I call
PropertyChanged(this, new PropertyChangedEventArgs("Self"))
it works like a charm.
Thanks all.
I don't believe there is a way of accomplishing exactly what you need with your current converter. As you mentioned, you could do the calculation in your ViewModel, or you could change your converter into an IMulitValueConverter.
From your specific scenario (the converter tied to a ViewModel class, and a few of its properties), I would lean towards implementing the logic in the ViewModel.
Hmm, you don't show the full implementation. But I think it should update, if the value bound to the GUI provides the PropertyChanged-Event.
Regards

Resources