Silverlight Custom Button content - silverlight

What would be a good way to have the text (content) of buttons per-client configurable in a SL 4 app? I'm still pretty novice w/ SL so this may seem trivial.
The issue isn't new. The system currently has a static XAML attribute for ButtonA's content as "Do Stuff" (Content="DoStuff"). Now one client wants that to read "Do Things". This will continue to crop up on occasion in arbitrary places across the system.
I have a dictionary available that will contain the custom text, but would LIKE (if possible) to be able to have a default value and only override if there is a dictionary entry.
Conceptually, it would be nice to be able to have:
<Button Content="Do Stuff" OverrideContentKey="ButtonAOverrideContent" />
where if the dictionary has a key of ButtonAOverrideContent, it will override it, but otherwise "Do Stuff" will show.
Is there a way to perhaps write a converter and make some entries in App.xaml that would then allow all buttons to conditionally override the content? What I've seen of converters looks like there's not a smooth way to pass information about the control (e.g. the override key) to them.

You can use a ConverterParameter property of a Binding to pass your override content key to a converter.
public class ReplaceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string key = (string)parameter;
var someDictionary = GetYourReplacementDictionary();
if (someDictionary.ContainsKey(key))
{
return someDictionary[key];
}
else
{
return value;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
In your App.Xaml resources:-
<local:ReplaceConverter x:Key="replacer" />
Then on a button:-
<Button Content="{Binding Source='Do Stuff', ConverterParameter=ButtonAOverrideContent, Converter={StaticResource replacer}}" />

Related

Is it possible to concatenate an imagesourece Uri in xaml

Hi I've been looking at ways to dynamically change an image Uri in xaml and in my research came across the following answer, which has certainly given me hope that what I really want to do might just be possible. In the original question the questioner wanted to swap the image itself, in my case I want to swap the directory where the image is located.
So when one looks at the answer that #Clemens provided one ends up with an images source being bound to a dependency property that is dynamically set when the form loads.
What I'd like to know is whether it would be feasible to set the location part of the uri dynamically (as per the logic that #Clemens is advocating and then simply append the Image name in the actual binding statement so that it might look something like this:
<Image Source="{Binding ImageUri & myImage.png}"/>
Essentially I have a number of buttons to which I would like to assign a default image og a size to be determined by the end user. To that end the Images would be stored in different folders in the application (in fact its a custom control) and then the relevant path bit of the URI would be set as per the suggestion in the referenced answer and I'd just append the Image name (which would be the same for the button irrespective of the size) and it would then have the correct image to display.
MainWindow.xaml.cs :
namespace MainWindowNamespace
{
public sealed class ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
string fullPath = Path.GetFullPath((string)value);
return new BitmapImage(new Uri(fullPath));
}
catch { return null; }
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{ throw new NotImplementedException(); }
}
}
MainWindow.xaml :
<Window
xmlns:imgConvert="clr-namespace:MainWindowNamespace">
<Window.Resources>
<imgConvert:ImageConverter x:Key="ImageConverter" />
</Window.Resources>
<Image ImageSource="{Binding ImagePath, Converter={StaticResource ImageConverter}}" />
</Window>

In Silverlight how do I set a buttons enabled state to be enabled based on items selected in a listbox?

I have a dialog that contains a listbox and the customary ok, cancel buttons. I would like set the enabled state of the ok button to be enabled only if an item in the listbox has been select. I would like to do this with bindings rather than in the code behind.
I may have been going down the wrong route but I have being trying to do something like the following
IsEnabled="{Binding ElementName=ProjectList, Path=??? }"
As you can probably see I have no idea what would go in the "Path"
If ProjectList is the name of the list box then you should be able to use SelectedItem.
You will need to bind through a converter that checks for the SelectedItem being null and returning false in that case.
So your XAML becomes:
IsEnabled="{Binding ElementName=ProjectList, Path=SelectedItem, Converter={StaticResource SelectedItemToBool}}"
and the selector looks something like this:
public class SelectedItemToBool : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Using Resourse.resx in WPF application to set color

I´m trying to make an application that has to be able to easily change a dll file which could change colors in the application.
I´m trying to use resource manager to do this but am having problems with setting color values so that the styles for views can easily accept it.
We know that(in this case) the background of a button takes in SolidColorBrush, and while
Value="Black" works,
Value={x:Static res:AppResources.Btn_Background}
which gives the string Black does not (current theory being that converters make the former work but not the latter).
This is all being done in wpf & mvvm.
Have you guys an idea about how this could be done.
Greetings
You could use a Binding:
Background="{Binding Source={x:Static res:AppResources.Btn_Background}}"
This will cause the CoerceValue to fire for the DependencyProperty controlling the background.
#Snowbear mentioned it may be a Color rather than a String, in which case you would need to provide a trivial IValueConverter.
public class ColorConverter: IValueConverter
{
#region IValueConverter Members
private Dictionary<Color, Brush> brushes = new Dictionary<Color, Brush>();
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
Brush brush;
var color = (Color)value;
if (!brushes.TryGetValue(color, out brush))
{
brushes[color] = brush = new SolidColorBrush(color);
brush.Freeze();
}
return brush;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Your specific issue is that you are bypassing the default string to Brush conversion and would need to handle that manually.
As sixlettervariables states, you'd can use a Binding if your source is a string, but that is probably overkill. At a minimum, you'd want to set Mode=OneTime on the Binding.
You can also create a custom MarkupExtension that performs the conversion.
Your conversion, whether it be through a custom IValueConverter or MarkupExtension, can leverage the BrushConverter class. So things like "Black" or "#000" will work as they do when defining the color in XAML like your first example.
EDIT:
Actually a markup extension that derives from StaticExtension, makes this easier:
public class BrushStaticExtension : StaticExtension {
private static BrushConverter converter = new BrushConverter();
public BrushStaticExtension() { }
public BrushStaticExtension(string member) : base (member) { }
public override object ProvideValue(IServiceProvider serviceProvider) {
return converter.ConvertFrom(base.ProvideValue(serviceProvider));
}
}
If you specify a string then XAML parser uses a converter from string which automatically creates a SolidColorBrush. As far as I understand at the moment Btn_Background resource is Color but it should be a SolidColorBrush instead.

WPF - Dynamically access a specific item of a collection in XAML

I have a data source ('SampleAppearanceDefinitions'), which holds a single collection ('Definitions'). Each item in the collection has several properties, including Color, which is what I'm interested in here.
I want, in XAML, to display the Color of a particular item in the collection as text. I can do this just fine using this code below...
Text="{Binding Source={StaticResource SampleAppearanceDefinitions}, Path=Definitions[0].Color}"
The only problem is, this requires me to hard-code the index of the item in the Definitions collection (I've used 0 in the example above). What I want to do in fact is to get that value from a property in my current DataContext ('AppearanceID'). One might imagine the correct code to look like this....
Text="{Binding Source={StaticResource SampleAppearanceDefinitions}, Path=Definitions[{Binding AppearanceID}].Color}"
...but of course, this is wrong.
Can anyone tell me what the correct way to do this is? Is it possible in XAML only? It feels like it ought to be, but I can't work out or find how to do it.
Any help would be greatly appreciated!
Thanks!
AT
MultiBinding is your friend here:
Assuming you have a TextBlock:
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource AppearanceIDConverter}">
<Binding Source="{StaticResource SampleAppearanceDefinitions}" />
<Binding Path="AppearanceID" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
And define a MultiValueConverter to return what you wish to see:
public class AppearanceIDConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
List<item> items = (List<item>)values[0]; //Assuming its items in a List
int id = (int)values[1]; //Assuming AppearanceID is an integer
return items.First(i => i.ID == id).Color; //Select your item based on the appearanceID.. I used LINQ, but a foreach will work just fine as well
}
public object[] ConvertBack(object value, System.Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
#endregion
}
Of course, you will need to set the converter as a resource in your Resource dictionary, like you did SampleAppearanceDefinitions. You can also ditch the multibinding and use a regular binding to AppearanceID with a IValueConverter, if you can get to the SampleAppearanceDefinitions collection through code ;).
Hope this helps
Even if it could be possible you'd better not do that this way, but instead use a dedicated property in your view model or in the code behind of your view if it has only a pure graphical meaning.
This property, say "CurrentAppearance", would expose a Color property you could bind from your Xaml :
Text="{Binding CurrentAppearance.Color}"
which is more understandable.
As a general advice : avoid to spoil your Xaml with plumbing code : Xaml should be as readable as possible,
particularly if you work with a team of designers that have no coding skills and do not want to be concerned with the way you are managing the data.
Moreover, if later you decide to change the way data are managed you would not have to change your Xaml.
MultiBinding might actually work if your list is on a viewmodel instead of a staticresource. I was suprised myself to see that the object passed on to the view is actually a pointer to the object on the model, so changing the object in the view (eg. typing in new test in the textbox) directly affects the model object.
This worked for me. The ConvertBack method is never useed.
public class PropertyIdToPropertyConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length == 2)
{
var properties = values[0] as ObservableCollection<PropertyModel>;
if (properties != null)
{
var id = (int)values[1];
return properties.Where(model => model.Id == id).FirstOrDefault();
}
}
return null;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Display WinForm Image in WPF application

I have a dll with quite a bit of System.Drawing.Image resources that I have wrapped into static properties so I can update them dynamically.
I would like to use the images through xaml in a WPF application, but the only way I can figure is to do it through the code behind manually.
Is there a way to do the winform to wpf image convertion on a static property in xaml?
You could bind to your images directly, using a converter. Here is an example in a window:
<Window.Resources>
<WinForms2WPFImageConverter x:Key="WF2WPFDrawingConverter" />
</Window.Resources>
...
This SO question has a drawing converter, which I adapted here as a ValueConverter.
public class WinForms2WPFImageConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
System.Drawing.Image i = (System.Drawing.Image) value;
using (MemoryStream drawingStream = new MemoryStream())
{
i.Save(drawingStream);
i.Seek(0, SeekOrigin.Begin);
return System.Windows.Media.Imaging.BitmapFrame.Create(drawingStream);
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new InvalidOperationException();
}
}
Of course, you need to account for namespaces in the declaration of the resource.
I advise not using static properties, in order to leverage INotifyPropertyChanged (or dependency properties), so that the display automatically changes when the properties point to other images.
(note: this was typed, not copied from VS, so there may be a syntax error somewhere.)
You could bind to your images using a Method in WPF. Here is an example in a link
http://microsoftdotnetsolutions.blogspot.com/2016/07/convert-winforms-image-to-wpf.html

Resources