I have a class named osmAppBarButton that inherits from AppBarButton (UWP) to which I have added a dependency property named ButtonState. (Enum Normal, Dim, Bright, Flash)
I have a Style used on all my osmAppBarButtons, that uses a DataTriggerBehavior to check the ButtonState and select the appropriate VisualState.
I was rather please with myself, as DPs and the VisualStateManager are all new to me. Then I hit a problem..
How can I change an osmAppBarButton's ButtonState from the ViewModel without breaking MVVM ? I thought about having a VM property for the ButtonState of each button in my view, but that would imply that the VM would have some knowledge of the View.
I think that the answer may lie with Attached Behaviours, but I haven't found an example that suits.
Any ideas ?
The way you get values from a viewmodel property to a dependency property is to use a Binding. Certainly not an attached behavior; I'm sure you could find some way to do that with an attached behavior, but just use a Binding.
`The viewmodel must implement INotifyPropertyChanged, and it must be the DataContext for the view where the appbar button lives, and you must not be shooting yourself in the foot by binding DataContext to something random in some parent of the appbar button.
Give the viewmodel a public property that raises PropertyChanged when its value changes. Bind to that property.
An enum like ButtonState with Normal, Dim, Bright, Flash values isn't the kind of thing a viewmodel should be aware of in a "proper" MVVM implementation. This isn't actually a silly point, either. I would suggest having the viewmodel expose its state through properties that express the viewmodel's state in its own terms (I could give you an example, if I knew what you were doing here). Maybe the viewmodel has a State that can be Normal, Busy, Error, Waiting -- those might map onto various ButtonState values. "Error" is a state of the viewmodel. "Flash" is one of many ways a view might choose to communicate a given viewmodel state to the user.
If the viewmodel expresses the relevant state using one or more properties with types other than ButtonState, you'd write a converter -- maybe a multiconverter -- to translate all that into a ButtonState value.
But it won't be the end of the world if your learning program uses ButtonState in a viewmodel, and that'll be simpler. So bind it to this:
private ButtonState _fooBarButtonState = ButtonState.ItsComplicated;
public ButtonState FooBarButtonState {
get { return _fooBarButtonState; }
set {
if (value != _fooBarButtonState) {
_fooBarButtonState = value;
OnPropertyChanged(nameof(FooBarButtonState));
}
}
}
XAML:
<local:osmAppBarButton
ButtonState="{Binding FooBarButtonState}"
/>
But if you'd like to go with my suggestion to use a different state enum in the viewmodel, converters are quite trivial to write. Let me know if you hit a snag, but if you got a dependency property and viewstates working, you'll get it.
Related
I am using the TreeView control from the WinrtXamlToolkit in a uwp app. I want to apply a different style to some TreeViewItems depending on a conditon so I created a class, TreeViewItemStyleSelector which derives from StyleSelector and I override the SelectStyleCore function.
public Style ResourceStyle { get; set; }
public Style ClassroomStyle { get; set; }
protected override Style SelectStyleCore(object item, DependencyObject container)
{
// control never reaches here.
// logic to apply style
}
Then in xaml I use it like this.
In Page Resources
<StyleSelectors:TreeViewItemStyleSelector ResourceStyle="{StaticResource AStyle}" ClassroomStyle = "{StaticResource BStyle}"/>
And later in the page.
<wxtControls:TreeView ItemsSource="{Binding StructureViewModels}" ItemContainterStyleSelector="{StaticResource TreeViewItemStyleSelector}" />
The problem is that the SelectStyleCore override is never called. Does anybody know why?
I am not yet sure what's the reason this doesn't work, although I have some theories. One is - this was never implemented. Perhaps at least at the root level it should work because it's an ItemsControl, but because of the way it's implemented (hierarchically) - the ItemContainerStyleSelector would have to be forwarded from the TreeView to the TreeViewItems, which it isn't.
I haven't had a chance to try to reproduce it yet, but if I were to try to fix it or work around it - I would first try forwarding that property in HeaderedItemsControl.cs - roughly where it says "// Note: this is where we would apply the HeaderTemplateSelector (...) (if implemented)". The alternative (if you don't want to modify the toolkit's code) might be to specify the template for the TreeViewItem and in the template - use a StyleSelector on template parts you want to be different for different data items.
From the perspective of object-oriented best practices, where should I place a variable or method needed in some children of a parent class, but not others?
Ex.
Classes Button, Knob, Lever, and Switch inherit from parent class Device.
Button, Lever, and Switch need a boolean isOn, but Knob does not. Where would you define isOn?
Lever and Switch need a method Throw() that toggles isOn; Button uses isOn but does not use Throw() to handle it. Does this affect your placement of isOn, and where would you define the Throw() method?
The above is purely an example; let's assume that there are distinct properties of each child class that distinguish it and that there are commonalities that make it reasonable to use the inheritence model discussed.
When only a sub-set of sub-classes share functionality, this can be expressed with an interface that contains the methods in question, which is only implemented by the sub-classes that need them.
public interface OnOffable {
boolean isOn();
void toggleOnOff();
void turnOn(boolean is_on);
void turnOn();
void turnOff();
}
class Switch extends Device implements OnOffable...
If one or more of the functions is moderately complicated, you can create a static utility function that helps prevent redundant code. In this example, however, the "complicated-ness" is the need to keep the on-off state.
In this situation, you can create an OnOffableComposer which (my preference) does not implement OnOffable.
And actually, since this particular interface can be completely implemented (meaning it needs no protected or abstract function), it can actually be a "simple" implementation of it:
public class SimpleOnOffable implements OnOffable {
private boolean isOn;
public class OnOffableComposer(boolean is_on) {
turnOn(is_on);
}
public boolean isOn() {
return isOn;
}
public void turnOn(boolean is_on) {
isOn = is_on;
}
public void toggleOnOff() {
turnOn(!isOn());
}
public void turnOn() {
turnOn(true);
}
public void turnOff() {
turnOn(false);
}
}
Here's how it's used:
public class Switch extends Device implements OnOffable {
private final SimpleOnOffable smplOnOff;
public Switch(boolean is_on) {
smplOnOff = new SimpleOnOffable(is_on);
}
public boolean isOn() {
return smplOnOff.isOn();
}
public void turnOn(boolean is_on) {
smplOnOff.turnOn(is_on);
}
public void toggleOnOff() {
smplOnOff.toggleOnOff();
}
public void turnOn() {
smplOnOff.turnOn();
}
public void turnOff() {
smplOnOff.turnOff();
}
}
Although the composer is "simple", this all demonstrates the concept of choosing composition over inheritance. It allows for much more complicated designs than single inheritance allows.
It sounds like the wrong abstraction all around. At the very least, Knob doesn't belong with the others. I might inject a class between Device and the three closely-related devices. Perhaps something like BinaryDevice:
abstract class Device {}
abstract class BinaryDevice : Device {
abstract void Activate();
abstract void Deactivate();
}
class Switch : BinaryDevice {
void Activate() { // activate the switch }
void Deactivate() { // deactivate the switch }
}
// same for Lever, which honestly is really just a Switch with a different styling and may not even need to be a separate object
class Button : BinaryDevice {
void Activate() { // activate the button, then immediately call Deactivate() }
void Deactivate() { // deactivate the button }
}
Knob can also inherit from Device, but at this point there is no common functionality for a Device so it's not clear why that universal common base class is even necessary. As further functionality is added to the various devices there may indeed be common functionality to push up to the base class. Indeed, there are well established refactoring patterns for dealing with generalization like this.
With the classes above, I imagine there would be error handling for trying to invoke an action in an incorrect state. For example, it's difficult to imagine a scenario where a Button would need anybody to call Deactivate() on it, since it de-activates itself. (Though just as a real-life button can become stuck, so too can this one if the action it invokes hangs for some reason.) But in any event even the Activate() and Deactivate() on the other objects would still need to check state. You can't activate a switch that's already active, for example.
The point is, the clarity of an object model starts to make itself more apparent when terminology and real-world modeling is more carefully considered. A lot of times developers try to shoehorn terminology into a handful of common terms in order to maximize their use of things like inheritance, and unfortunately this often results in the wrong abstraction and a confused domain model.
Build your objects as they naturally exist, then look for patterns which can be abstracted into common functionality. Don't try to define the common functionality first and then force objects to fit that mold.
In general, I would say that if an element of a parent class is needed in some but not all of the children then an intermediate parent should be introduced.
When defining an inheritance hierarchy, it's a logical assumption that the children of a parent should share all properties of that common ancestor. This is akin to the way a biological taxonomy would work, and it helps to keep the code clean.
So let's have a look at the objects in your system (we'll use the "is a" relationship to help us figure out the inheritance hierarchy):
Button, Knob, Lever, and Switch
Each of these might indeed be called "Devices", but when we say "devices" most people will probably think of digital devices like phones or tablets. A better word for describing these objects might be "controls" because these objects help you to control things.
Are all objects Controls? Indeed they are, so every object will have Control as a parent in its inheritance hierarchy.
Do we need to further classify? Well your requirements are to have an on/off status, but it does not make sense for every control to have on/off status, but only some of them. So let's further divide these into Control and ToggleControl.
Is every Control a ToggleControl? No, so these are separate classes of objects.
Is every ToggleControl a Control? Yes, so ToggleControl can inherit from Control.
Are all objects properly classified and are all parent attributes shared by all children? Yes, so we're done building our inheritance hierarchy.
Our inheritance hierarchy thus looks like this:
Control (Code shared by all controls)
/ \
/ \
Knob ToggleControl (Code shared by all controls that can also be toggled - Adds isOn)
\
\
Button, Lever, Switch
Now, to the other part of your question:
Lever and Switch need a method Throw() that toggles isOn; Button uses isOn but does not use Throw() to handle it. Does this affect your placement of isOn, and where would you define the Throw() method?
Firstly, "throw" is a reserved word (at least in Java), so using method names that are similar to reserved words might cause confusion. The method might be better named "toggle()".
Button should (in fact it must) use toggle() to toggle it's isOn since it is a togglable control.
I'm having a difficult time explaining my problem, so I'm just going to make it as simple and hope it does the job. I'm using Qt5 with QtQuick 2.0.
I've created a MyListModel class that inherits from QAbstractListModel, and holds items of type MyListItem. I use it in a QML ListView as a model: myListModel, and the delegate displays a quantity property from MyListItem, in a lovely TextInput box. Everything works fine.
However, when I change the quantity value from the delegate, the items in the model aren't updated. I know they're not updated, because my setQuantity(long desired_quantity) function, a member of MyListItem, does not run. Long story short, I can't figure out how to actually call the setQuantity function from within the delegate. I can do it manually by adding Q_PROPERTY(long quantity READ quantity WRITE setQuantity) to MyListItem, and then using setContextProperty() to expose a MyListItem myTemp object to QML, and then calling myTemp.quantity = 10. But clearly, if the delegate can't write to the quantity property (it can only read from it), it's not doing the job.
Can somebody point me in the right direction? I feel like I've tried everything the Qt designers could have possibly expected, and I get nothing. And I can't find any documentation that clearly addresses my issue.
The TextInput box will not update your c++ model automatically, you have to do this by yourself. You can do this by adding a slot or Q_INVOKABLE method to you model:
//add a slot to you model
public slots:
setDataInModel(const int index, const QVariant &value);
//or add Q_INVOKABLE method:
public:
Q_INVOKABLE setData(const int index, const QVariant &value);
You have to implement one of these methods so that it changes the appropriate data row in your model. Do not forget to call the dataChanged method inside of the method after update. You then have to call these methods from QML delegate manually when the TextInput is updated:
onAccepted: {
model.setDataInModel(index, text)
}
Here index is a property that is defined in each delegate and text is the text from your TextInput.
Has anyone had a go at creating a view that sorts a collection? The ICollectionView interface is present, and it claims to have the same responsibilities as its WPF / SL counterpart (sorting, paging, filtering), however, unless I have missed something, there are no sort
methods / properties on the interface.
I would be interested to find out how to take a collection of items then sort them via a view in WinRT.
Note, I know I can do this manually, however, I want to see how a sorted collection interacts with the WinRT theme transitions that appear to add visual effects when sorting is performed.
Unfortunately, there's no support for sorting a collection view in Win8 (nor filtering or grouping). The only way to do this is to manipulate the data source directly, then assign it to Source property.
This has been discussed as an improvement for the post-Win8 timeframe. Wish I had better news :)
Linq seems to be the suggested way now that Sort and Filter have gone AWOL.
So you could adopt something like this in your model:
private MyDataSourceProvider dataSource;
private ObservableCollection<MyType> sortedDataBackingField;
public ObservableCollection<MyType> SortedData
{
get
{
return sortedDataBackingField;
}
set
{
sortedDataBackingField = value;
NotifyPropertyChanged("SortedData");
}
}
public void SortByName()
{
SortedData = new ObservableCollection<MyType>(dataSource.Entities.OrderBy(
entity => entity.Name));
}
public void SortByAge()
{
SortedData = new ObservableCollection<MyType>(dataSource.Entities.OrderBy(
entity => entity.Age));
}
Hook SortByName and SortByAge up to your UI in the pattern of your choice, and simply bind to the SortedData property:
<ItemsControl ItemsSource=”{Binding SortedData}”/>
Edit: With reference to transitions, you should find that this approach will trigger the AddDeleteThemeTransition for the items that you've sorted; just add something like this inside the ItemsControl:
<ItemsControl.ItemContainerTransitions>
<TransitionCollection>
<AddDeleteThemeTransition></AddDeleteThemeTransition>
</TransitionCollection>
</ItemsControl.ItemContainerTransitions>
I'm rather new to XAML and Silverlight. I have a XAML page and a code behind class for it. In the class, I have a protected read-only property. Can I bind a control to that property? Trying to specify the root element of the XAML as the DataContext (by name, as an ElementName) causes a designer error "Value does not fall within the expected range."
EDIT: I'd like to do in the designer-fiendly way. I understand I can do everything (including control population) from code; that's not the point. Can I have the designer recognize and display the properties of my code-behind class? Not one ones from the base (PhoneApplicationPage) but the ones that I define?
Your code behind should be the datacontext.
For example on a main page code behind:
public MainPage()
{
InitializeComponent();
DataContext = this;
}
You should be able to bind to the protected property but only one way ie from the property to the xaml. As it is read-only you will not be able to get the value if it is changed on the page by the user.