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.
Related
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.
I have a Xamarin.Forms xaml page in which I am using a ListView to allow the user to pick a single item out of a list. I have bound the ListView's SelectedItem property to a property on my ViewModel and this works fine. As soon as the user changes the selected item the property in my viewmodel updates as well.
However, even though I initially set the property in my ViewModel to one of the values from the list, when the page loads the ListView's SelectedItem property is null, which in turn sets the ViewModel property to null as well.
What I need is the other direction, I want the ListView to initially select the item that i've set in the VM property.
I can hack together a solution by writing extra code in the code behind file to explicitly set the initial selected item, but this introduces additional properties and complexity and is quite ugly.
What is the correct way to set the initial selected item of a ListView who's selected item is bound to a viewmodel property?
-EDIT-
I was asked to provide the code that I'm using for my binding.
It's very simple, standard:
<ListView x:Name="myList" ItemsSource="{Binding Documents}" SelectedItem="{Binding SelectedDocument}">
the view model that is set as the binding context for the listview is instantiated before the page is created and looks like this:
public class DocumentSelectViewModel : ViewModelBase
{
private Document selectedDocument;
public List<Document> Documents
{
get { return CachedData.DocumentList; }
}
public Document SelectedDocument
{
get { return selectedDocument; }
set { SetProperty(ref selectedDocument, value);
}
public DocumentSelectViewModel()
{
SelectedDocuement = CachedData.DocumentList.FirstOrDefault();
}
}
SetProperty is a function which simply rasies the INotifyPropertyChanged event if the new value is different from the old one, classical binding code.
I am a little rusty on XAML but don't you need to make the binding two-way?
E.G.
{ Binding SelectedDocument, Mode=TwoWay }
As long as the SelectedDocument property change raises the INotifyPropertyChanged event then you should get the desired effect.
If you replace
public DocumentSelectViewModel()
{
SelectedDocument = CachedData.DocumentList.FirstOrDefault();
}
By
public DocumentSelectViewModel()
{
SelectedDocument = Documents.FirstOrDefault();
}
Does it work for you ?
I had a similar problem that has been resolved this way...
You can use ctor DocumentSelectViewModel for set initial value. Honestly I dont like to make some job in ctor block but Xamarin.... You dont need DocumentSelectViewModel method. It will work.
public DocumentSelectViewModel ()
{
SelectedDocument = Documents[0]; //or any your desired.
}
I have an Icon which has a Content (one to one) relationship.
public class Icon
{
public virtual Content Content {get; set;}
}
By default, it is lazy loaded which is what I want.
However, at some point in the code, I need to check what kind of Content is, Content being polymorphic, something like
if(icon.Content is TextContent)
{
...
}
Icon is part of another association and it is automatically obtained by the NHibernate, I do not get it manually.
What is the recommended way of checking for the actual type in this situation?
I can have a specific property like ContentType which will be an enum in order to identify the actual content type, but I am looking to know if there's a different way.
If you want to do that kind of check, you have to remove the proxy from the property.
There is a few ways to do it:
If you have access to the session call:
session.PersistenceContext.Unproxy(icon.Content);
Implement a virtual method (in a base class if possible) that forces the removal of the proxy by returning the instance with the proper type.
public virtual U As<U>() where U : YourType {
return this as U;
}
Disable the lazy initialization of the property.
This is very similar to another recent question.
To add to csanchez's list, a fourth method is to add a Self property to the Content base class that returns the un-proxied type:
public virtual void Self
{
get { return this; }
}
And a fifth method is to use 'lazy="no-proxy"` in the mapping as described on Ayende's blog.
Thanks for the suggestions but meanwhile I found an interesting solution, better I think.
Using the Visitor pattern, I can define an IconContent visitor and pass an Action to be executed to it.
For example, suppose there is a TextContent and an ImageContent, it will be something like this:
IconContentVisitor.Func(()=> { Console.WriteLine("this is TextContent"; }, ()=> { Console.WriteLine("this is ImageContent"));
Idea came from here: http://mookid.dk/oncode/archives/991
How do you disable the selection single item from a GridView?
I have a GridView with it's ItemsSource bound to an IEnumerable<SampleDataItem>. I'd like to be able to programmatically not allow the selection of some items in the list while allowing selection of the others.
While I haven't done this, you should be able to use an ItemContainerStyleSelector on the GridView, the method gives you the container (GridViewItem) and the item you're binding to. From there you can set the IsEnabled property on the GridViewItem to false which makes it unselectable.
You'll also probably need to select a custom style as well since the default GridViewItem style will customise how a disabled item will look.
Update DataTemplateSelector Solution
public class IssueGridTemplateSelector : DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
var selectorItem = container as SelectorItem;
if (item is Issue)
return IssueTemplate;
selectorItem.IsEnabled = false;
selectorItem.Style = RepositoryItemStyle;
return RepositoryTemplate;
}
public DataTemplate IssueTemplate
{
get;
set;
}
public DataTemplate RepositoryTemplate
{
get;
set;
}
public Style RepositoryItemStyle
{
get;
set;
}
}
Nigel's answer is great. I just added some attached properties to the WinRT XAML Toolkit that should make it simpler to do if you are populating your GridView using the ItemsSource property binding.
For me the usual way to modify the GridViewItem properties then was using GridView.ItemContainerStyle property. Using that method you would need to specify the IsEnabled property using a style and style setters don't support bindings in WinRT. Using the ItemContainerStyleSelector might be one way, but it requires defining a custom class.
I have created a GridViewItemExtensions class with an IsEnabled property that you can set on any control in your GridView.ItemTemplate like this:
xmlns:xyzc="using:Xyzzer.WinRT.Controls"
xyzc:GridViewItemExtensions.IsEnabled="{Binding IsEnabled}"
The property has a behavior of finding the GridViewItem in its ancestors visual tree and keeping its IsEnabled value synchronized to the GridViewItemExtensions.IsEnabled value set on its descendant.
Then as Nigel said - you still need to extract the template from a GridViewItem and modify it so the disabled items don't look out of place.
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>