Swapping images based on variable - c#

I have an application that is using XAML and C# (MVVM) to create a interface that allows you to start and stop a camera feed.
What I would like to do is to switch between a OFF and ON image depending on the variable IsOn.
I know how to set the image in the UI Manually,
<Image Source="/MyApp.WpfUI;component/Resources/Images/Webcasting.png" />
but I am not sure how to best change the image dynamically based on conditions. I have considered IF statements, but am not sure how to go about that.
Does anyone have any advice or ideas?

One answer would be:
Binding the IsEnabled attribute of your control that displays the stream to a property in your code that returns a boolean.
In your View:
<Image IsEnabled={Binding IsOn} Source="/MyApp.WpfUI;component/Resources/Images/Webcasting.png" />
In this property's getter, put your conditional statements to determine whether or not to return a true or false.
In your ViewModel:
public bool IsOn
{
get
{
if(<some condition>)
return true;
else
return false;
}
}
Notes:
Don't forget to use your implementation of INotifyPropertyChanged to alert the UI when necessary.
If you implement a setter, you could have a button on the View that would toggle the value giving you manual control.
Binding can be used to alter the Source of the stream as well using the same technique as above. I.e., the getter would return the path to the video stream or the path to a static image that says "Video Off". However, this is dependent on whether or not the control you're using can handle that. Instead of the IsEnabled attribute, you would use binding with the Source attribute.
Here a couple links that will show you some similar implementations of this:
High Overview of WPF (MVVM) w/Binding
Simple Binding Example
Good luck.

You have two options here. You can either perform this manually using an if statement as you mentioned in your question, or you can create a DataTrigger & assign it to your control's ControlTemplate.
DataTriggers allow you to set property values when the value of a particular data object matches certain conditions you specify in the XAML. I'd recomend reading the MSDN documentation on DataTriggers for some basic examples of how these work.

Related

x:Bind in UWP (Universal Windows Platform)

Right. So moving from WPF to UWP, I'm trying to use x:Bind to get compile-time benefits. Simple scenarios work fine; however I have found a number of issues that I was not able to solve. They are all related, so I thought I'd post them in one place:
I haven't been able to make Intellisense work with x:Bind. I have set DataContext (as well as d:DataContext just as we do in WPF) both in XAML and in the constructor, but it won't show members no matter what. Has anyone done this successfully?
Then I read somewhere that in UWP, DataContext is always set to Page's code-behind (really??) and that I need to define a ViewModel type property in the code-behind and then use that property in x:Bind. Is this correct? I tried it and it works but gives rise to the next question.
If I define a property of ViewModel type in Page's code-behind, Any sub-properties that raise PropertyChanged notifications do not update the UI. For example, if the code-behind property is named Game (of type GameVM) and there is a public property in GameVM named Player (of type GamePlayer), and in turn GamePlayer contains a property named Name, the x:Bind path will look like {x:Bind Path=Game.Player.Name}. But if I do this, any change notifications raised from within Name property do not update Page's UI.
One alternate I tried was to listen to PropertyChanged at each level and then bubble it up the hierarchy, but that hasn't worked. Even if it does, doing this seems a bit too much work. In WPF sub-properties like Game.Player.Name work properly without having to doing property change bubbling. Or am I missing something?
Right. After playing with it for a few days and searching numerous references, here are my findings:
{x:Bind} lacks design-time support. The feature is on the wishlist though. You may want to upvote it there.
(The new version of Visual Studio 15.4.4 does support Intellisense in {x:Bind}in the required way.)
{x:Bind} uses code-behind as its DataContext. So you need to define a public property of your ViewModel type in the code-behind and then use it in your {x:Bind} path.
As pointed out by IInspectable, the default mode for {x:Bind} is OneTime, unlike {Binding} which uses OneWay or TwoWay in almost all cases. So you need to explicitly specify Mode in your binding. People coming from WPF should take special care of it.
Sub-properties that implement notification change work perfectly fine in {x:Bind}. There is no need of bubbling these notifications upwards in the property hierarchy. The problem I was facing (#3 in the question) was because my sub-property was of type List<T>. I changed it to ObservableCollection<T> and it started working.
Hope this works somebody down the road.
Well as a beginner, the only question I can answer for you is the first one. Intellisense does not work inside the {x:Bind}. The members are never shown there in UWP for some unknown reasons. As for the next two questions of yours, I am still working on them.
I ran into the same challenge that you have seen. In my experience, in order to create the compile-time binding and have it update with custom objects as properties, the Page class seems to need to know about the data context and custom objects... all you need to do is reference them in the code behind, and then bind to them in the XAML. This creates the code generation objects it needs.
For example, I have a viewmodel, CustomerViewModel that is bound in XAML. That viewmodel also has a property of type IGuest. In order to use the guest object and have it update properly, I came up with this in the code behind...
CustomerViewModel vm
{
get
{
return (CustomerViewModel)DataContext;
}
}
IGuest g
{
get
{
return vm.CurrentGuest;
}
}
public CartGuestControl()
{
this.InitializeComponent();
}
You don't need to assign any of the UI data contexts from the code behind... simply reference the datacontext that is bound in XAML. When binding to any straight viewmodel properties, I use {x:Bind Path=vm.IsEditing, Mode=OneWay}. For binding to any of the guest properties, it looks like this, {x:Bind Path=g.FirstName, Mode=TwoWay}. You could do something like this for your Player object.
I have run into times where x:Bind simply won't do what I expect it to do no matter what I try. This can usually be solved by breaking things out into smaller user controls with more specific data contexts or by using "regular" Binding.

Programmatically filter custom properties

I have an existing custom control library with controls which may contain properties: HeaderStyle, ModalStyle, Collapsable, etc...
In the user interface the program is currently displaying a categorized list of these properties. I am trying to update this code to hide properties they dont normally use. I have a list of properties to hide/show based on button click but I am not sure how I can hide these fields programmatically.
I would like to retain any values entered into the fields before hiding and re-display the values if the fields are shown again.
Here is a property that current exists but would like to be hidden/shown on toggle.
/// <summary>ModalStyle property for control</summary>
[XmlAttribute]
[DefaultValue(Utility.Common.Enumerations.ModalStyle.None)]
[Category(PropertyCategories.Rendering)]
[Description("Modal dialog style")]
public ModalStyle? ModalStyle
{
get { return control.ModalStyleActive; }
set { control.ModalStyle = value; }
}
My original though was to do some variant on #if DEBUG but use my own Conditional however I was unable to find a way to change my conditionals via button/toggle.
Can anyone please help with a solution to my problem? I have 20-30 controls with 20 to 30 properties that would like to be filtered.
I have two suggestions that, while they may not give you the exact functionality desired, will keep your solution much more straight forward.
First:
Since you are the library developer you should just decide what properties you want other developers to have access to though the IDE properties window. If a property is seldom used or not very useful through the IDE then just place the [Browsable(false)] attribute on it.
Second:
If you really want all properties to be visible in the IDE properties window, but want to give individuals a way of hiding the more advanced (or less used) ones, just throw them all in an 'Advanced' category. The user can then simply collapse that category and forget about them.
Also: Take a look at Oliver's answer to this question:
[how-to-show-or-hide-properties-dynamically-in-the-propertygrid]
I'm not sure to understand what you are trying to achieve.
When you use Attributes, those are static to the class. So, in your case, when you toggle a show/hide on an object, it's on an instance of the object. Also, you cannot change an attribute value at run-time.
Maybe you should try an alternate solution like creating a global
map<pair<type of object, property name>, is shown>
and update that accordingly from your editor.
And if you want to use something like a property grid, you will have a problem since it won't check your map, but it can be fixed. You could create a new class at run-time and make it a proxy to your current instance. (check on the net how to achieve that, but it's quite simple. There are 2 possibilities: compile from a string or use the ILGenerator.
Hope this help.

How can I automatically verify that all controls in my views are set with binding?

Looking for a way to automatically verify, using unit-tests for example, that all controls in my WPF application are set to Binding.
I'm using data-binding to enable localization in the application.
For example, a TextBlock control in a view will have it's Text property binding to 'SomeLocalizedLabel' property in the view model.
I need to make sure that I won't miss any control, and all my 'TextBlock' controls have their 'Text' property bound to something.
I can check the correctness of the localization itself in the ViewModel level.
I can check that all public ViewModel properties are bound to something in the view using the Caliburn.Testability assembly or some other method.
The thing that missing here is to test the View level.
UI testing framework is not the solution I'm looking for, because I wish for something that can be written and executed fast.
See my post here:
How to check if a XAML element supports AutomationId attribute
You could use the mechanisms mentioned to go through all your XAML and look at the Text properties of elements, and decide if they have missed a Binding.
LocBaml is a tool that goes through the XAML to extract localizable properties....your rolling your own localization technique...but I'm sure you can adapt that to extract check "Text" properties and see if they have a binding, then produce a report where they are not.

When to use Dependency Properties

I sometimes think I maybe using Dependency Properties unnecessarily. When do I need to use it? When I have a property that dependes on other properties? Say I have a Color property that I want it to be dependent on properties Hue, Saturation, Luminosity do I use a dependency property? Or what do I use? I controls thats bound to Color to update when properties Hue, Saturation, Luminosity are changed.
for now what I did was
public byte Hue {
get { return _hue; }
set
{
if (_hue == value)
return;
_hue = value;
NotifyPropertyChanged("Hue");
NotifyPropertyChanged("Color"); // to update controls bound to color
}
}
But I think this is not the right way of doing things? If I have more properties that affect color, I will have 1 extra line in all those properties?
You should only use a DependencyProperty when you want to be able to bind its value to something through XAML, e.g.
<local:MyObject MyDependencyProperty="{Binding ...}" />
Update: as mentioned by Ian below, dependency properties are also required if you want to be able to animate your property or set it through a style
If you do not need to work in this way then it is unnecessary. e.g. If you just want to be able to set the value to a constant through XAML (as below) this will work without using a DependencyProperty
<local:MyObject MyRegularProperty="Some Value" />
Similarly, if you want to bind to the value of a property on (for example) your view model:
<TextBlock Text="{Binding MyViewModelProperty}" />
then you do not need to use a DependencyProperty. Provided that you implement INotifyPropertyChanged then the Text will still be updated when the property changes.
Edit: on re-reading your question, I am not sure whether or not your situation will be affected by whether or not you use a DependencyProperty - if I'm reading it correctly, all you want to do is cause a number of properties to be updated on the UI when any one of those properties changes, right?
I don't think there is anything wrong with how you are implementing things at the moment (i.e. raising a lot of PropertyChanged events in each setter), but if you aren't keen on in then you could try having a single property that exposes relevant child properties to bind to that are all calculated:
class ColorWrapper
{
public Color Color { get; set; }
public byte Hue
{
get { return this.Color.Hue; } //or however this is calculated
}
Then have a Color property on your ViewModel that raises the PropertyChanged event and bind to that through the View:
<TextBlock Text="{Binding Color.Hue}" />
As I said, I wouldn't say that this is particularly an improvement on what you have already though.
The general rules are:
For XAML controls, use dependency properties;
For data (which you bind to in the interface), use INotifyPropertyChanged.
There are exceptions, but they are rare.
Another use of dependency properties is with navigation journal. Custom dependency properties on a Page with Juornal flag in the meta-data are included in the state that WPF saves for the page.
Remember that Dependency Properties, although they allow Binding either as a source or a target, are also Thread-Sensitive, and when serializing you will have to use a surrogate, serialization as DependencyObject isn't serializable.
Oh, and Equals and GetHashCode are sealed :(
Another usage of DP is Attached Property. Attached property is a type of DependencyProperty where the property can be used in any other controls.
For example, you can declare AttachedProperty in class MyAttachedProperties and used it for TextBlock, Button, Label,...
Some examples of Attached Properties: Grid.Row, Grid.Column. A customized one:
public static readonly DependencyProperty DarkThemeProperty =
DependencyProperty.RegisterAttached("DarkTheme", typeof(Theme), typeof(Page));
public static Theme GetDarkTheme(DependencyObject obj)
{
return (Theme)obj.GetValue(DarkThemeProperty);
}
public static void SetDarkTheme(DependencyObject obj, Theme value)
{
obj.SetValue(DarkThemeProperty, value);
}
I was stepping into the "trap" of DependencyProperty often.
At some point I realized that every single Change of any value is triggered somehow and somewhere, that can be an algorithm, a process, a user-input... and a lot of things, but NEVER it just changes by itself.
Get control about that triggers, hook directly at source and you never need DependencyProperty and even no INotifyPropertyChanged. I mean maybe I do something wrong or right, but all problems, and they are sometimes of serious difficulty, I solve with only RoutedEvents and Properties { get , set } -> And inside of get, set you can do SO much. Everthing that cannot be solved here, can be done with AddHandler and don't forget to RemoveHandler when not needed anymore.
Also needed is a solid understanding of Threading and Dispatching in some cases.
Also needed is a good knowledge how to work with Lambda expressions and Actions.
(Probably not useable for windows phone etc. applications, guessing)
Respectively: A serious drawback is coding control and effort. For that approach I need to write more Code and have better documentation, the big advantage is better understanding what is actually happen within your application and what could happen, what are the extends. There is NO drawback in performance, it is even faster, because when you hook directly into your triggers, you are using the lightest and most appropriate form of an Approach - Executing Code ONLY when it is necessary and only that heavy that it is necessary.
Finally: DependencyProperties could make sense in very responsive applications where you actually DON't KNOW the possible relations and reactions. That could be over a million possible cases -> You don't want to have control over those, you would never finish your product.
Caveats: Not everything that looks like it is producing a ton of unknown cases are unknown. You can work with RANGES (from x to y) and write algorithms to regain control over thousands of possible cases with just one method.
So that are my two cents: DependencyProperties and INotifyPropertyChanged is not needed in most of the cases and just a way of having an easier coding life at the cost of actually understanding your product and (sometimes) performance.
(Notification to myself: I write this because I just came into a situation where I was thinking I need DependencyProperty, this time for real.. but no.. one hour of thinking and the solution was easy, found the trigger.)

Default ValueConverter for a binding

Is there a way to get WPF to automatically apply a Converter to all bindings of a specific type?
I've seen this question, but it covers a different case (localisation) and thus has no satisfying answers.
My problem: I've got model classes containing Commands, which I would like to bind to WPF Commands. Since the model classes are toolkit-independent, I cannot implement WPF's ICommand there. Instead I have a CommandConverter which wraps CommandModels into WPF ICommands:
<Button Command="{Binding MyCommand, Converter={StaticResource CommandConverter}}" />
This works quite well, except that it is easy to forget about the Converter= and WPF doesn't give any indication that the binding failed.
My question is now: Is there a possibility to force WPF to always a apply a converter to specific types of bindings? Or, alternatively, how can I get WPF to give me proper errors when a Command binding fails?
I don't think you can without either sub-classing Button (you probably don't want to do this), or defining your own attached property and using a TypeConverter attribute on it.
If you want to go with using a default converter via the TypeConverter attribute on a new attached property, you can look at Rob Relyea's informative post here, or MSDN here.
While I've never done it, would it be possible to define a custom Markup Extension? That should cause the value to be sent to your class that implements the Markup Extension, and then from there you can return an ICommand that the Command property is expecting.
As I said, I've never created one my self, but a Google Search seems to bring up a few articles on how to do it.
Check the debug output window. Normally you get to see the binding errors there.

Categories

Resources