WPF: Activate Trigger when a MVVM bound property changes - wpf

somehow I am going in circles here. Please forgive me if the answer to this question is obvious.
I want to react to changed properties in the ViewModel in the View. When the properties (bool) change the View should start an animation (BeginStoryBoard).
Actually in my application there are 4 of these properties each with its own name in the VM and two desired animations each (hide/show) for the respective 4 container view elements.
When setting these Triggers (tried DataTrigger/Trigger/EventTrigger) directly in the respective container elements (all of them of custom type SizerControl derived from ContentConrol) wpf gave me errors suggesting using a style. When setting a style directly in the container elements I got: "The tag 'Style.Triggers' does not exist in XML namespace ..."
But when using a style in a global ResourceDictionary I am at a loss how to bind to the 4 containersto get the "input" value for the trigger.
Do you have a suggestion how to solve this from an architecture pov? Maybe I am already down too far the wrong path to see the obvious solution.
Thanks a bunch,
Hinnerk

You can do this with a DataTrigger and a StoryBoard.
MSDN has a full sample describing the process, with code, documented in How to: Trigger an Animation When Data Changes.

Related

Mvvm light wpf navigation

What I want to achieve. A navigation service for MVVM Light WPF where I can easily say NavigateTo(View URI or ViewModel and a string name of the framework element that should present the View or ViewModel).
I first tried the View First approach from here.
https://stackoverflow.com/a/28968560/5272185
Problems I found with it was that the Frame frameworkelement seems to run sandboxed, and even though I set the view's datacontext to bind to a viewmodel retrieved from my viewmodellocator I seem to get a different instance inside the Frame. Also styles seem not to be inherit down into the Frame and the MVVM Light Messenger's messages do not seem to bubble up from the View shown inside a Frame.
Also the code to find the Frame element failes if the Frame is located within a ViewBox. I have no clue why but if I just remove the ViewBox it finds it correctly.
I ignored the ViewBox issue (removed the ViewBox) and changed the NavigationService to store ViewModelBase types instead of URI, and I changed the code to find a FrameworkElement of type ContentControl instead of Frame, set the ContentControl's content instead of a Frame's source. This so I should not run into the sandbox problem. This worked, but I now have no good way of switching to a detail view (using the same ViewModel as datacontext for multiple views).
Questions
When using a ViewModel first NavigationService as explained above, is there an easy way to show a detail view (sharing a ViewModel) without code duplication?
In case of a View first navigationservice exactly like the code in the link. Is there a way to make the Frame inherit the correct datacontext and styles (not running sandboxed at all)?
Can someone explain why the VisualTreeHelper code in the provided link does not find a framework element if the element is inside a ViewBox?
I should also mention that I have tried the approach to make a CurrentVM property and CurrentDetailMode property on the ViewModel and bind a ContentControl's content to the CurrentVM property and used DataTemplates with DataTriggers (bind to CurrentDetailMode) to set the corresponding View(s) to the ViewModels. According to this post.
https://rachel53461.wordpress.com/2011/12/18/navigation-with-mvvm-2/
It works well and supports detail views. My goal with the navigationservice is that I want to add all views or viewmodels to the service in one place. Not having to create the CurrentVM and CurrentDetailMode properties on every ViewModel that should be able to show different content / views. And I would prefer an easier solution than manually setting up Datatemplates with special DataTriggers for supporting "Detail" views. Also the navigation service discussed has a history queue so one can go back.
I managed to solve / answer my own questions
Just create a dumb ViewModel class for the Detail view, provide it with the (Main)ViewModel instance and make that ViewModel instance a property so you can bind to it. Done! Easy after all, and with Dependency injection it can become a breath.
See this link page.DataContext not inherited from parent Frame?
I solved this one and tracked it in the following separate question. See answer here
WPF ViewBox blocks VisualTreeHelper search

Accessing a 3rd-party ContentTemplate-internal control

I'm using a 3rd party control (in this case, Telerik's RadChart control), which has a complex inner ControlTemplate that encompasses several elements of the chart. Unfortunately, not all parts are exposed explicitly for me to style, and I find myself wanting to set a property on a particular sub-element inside the ControlTemplate, either via XAML or via code. After struggling with the XAML for a while, I settled for a code-centric approach, but I'm still stuck.
Using Snoop, I can see that the top-most ChartArea control (which I can access) renders an AxisX2D object named PART_AxisX, which in turn has a template which contains the PART_AxisLabels object, which is the one I need to style. (Incidentally, the property I want to set is AlternationCount, but I couldn't find a less hacky way of getting to it).
I tried to use the ControlTemplate.FindName method (as shown here) to get the AxisX2D object, and then again on that object to get the AxisLabels object, but FindName always returns null:
var chartArea = myChart.DefaultView.ChartArea;
var visualAxisX = chartArea.Template.FindName("PART_AxisX", chartArea) as AxisX2D;
even though Snoop confirms that chartArea is, in fact, the AxisX2D's TemplatedParent. I checked in the debugger and I could find PART_AxisX in chartArea's internal Template property.
So my questions are:
1) What am I doing wrong here?
2) Is there a better way to approach this that isn't as roundabout as this?
The solution is to wait till after the Loaded event has occurred on the Control.
When this event has occurred you know that the Template has been applied and the visual tree has been built for the control, and so you can then access the elements using FindName.
http://blogs.msdn.com/b/mikehillberg/archive/2006/09/19/loadedvsinitialized.aspx
Slightly related link given here for case when using a Content Template on a ContentControl.
Why would 'this.ContentTemplate.FindName' throw an InvalidOperationException on its own template?

WPF - how to bind to source in different page?

Could anyone answer a really frustrating newbie question please?! I've been hunting for an answer for a few days & have found answers to similar questions posed, but nothing that exactly solves my issue.
I'm trying to bind a textbox to the currently selected item in a listview (which itself is bound to an Observablecollection of objects, not sure if this matters).
The listview is in RecentEntities.xaml & the textbox is in Relationship.xaml, both of which are positioned on the Main Window from within Maincontrol.xaml. So they're in the same namespace but they're in different pages so using ElementName doesn't work as this just seems to look within the current page.
The issue I'm having is when trying to define the source of the textbox binding in Relationship.xaml, how do I reference the selected listview item in RecentEntities.xaml? I wondered about using RelativeSource, but this seems to only let you navigate up the tree to an ancestor of the current control. Because of how MainControl is set up, I would need to travel up to the parent of the textbox, then to a sibling of the parent then down to a child of a child of it in order to get to the listview!
I've explored (possibly not in enough depth) other options like resources, data context, including header files and have read something about Merged Resource Dictionaries but to be honest the more possibilities I explore, the more confused I'm getting about what I need to be doing.
Is this really as complicated as it seems?! Any pointers or help would be brilliant, thanks for taking the time to answer :) I haven't posted on here before, so if you need any code snippets please let me know.
Can you create a ViewModel that both Views will use? Have the selected item in your listview bind to a property in the ViewModel and have the textbox bind to the same property. As long as both views reference the same instance of the viewmodel, it should work.
With two XAML files you will have to use the model or viewmodel (depending on your choice of architecture) for synchronization.
For the listview you can use the SelectedValue to bind to a property, use Mode=OneWayToSource for this binding since you just want to update the property, not change the selection in the listview itself.

Access Elements inside a DataTemplate... How to for more than 1 DataTemplate?

I've got 2 DataTemplates defined for a Listbox Control. 1 Template is for the UnSelected State and the other one is for the Selected State(showing more detail than the UnSelected State).
I followed the example here:
Link
about how to access the Elements inside the DataTemplates from Code behind.
I get it right, but it only finds and returns an element of the UnSelected DataTemplate. But when i search for an element in the Selected DataTemplate i get a NullReferenceException.
What could i be doing wrong?
Setting keyboard focus might be one reason you need to access the datatemplate elements. MVVM will not solve that issue and the FocusManager doesn't set keyboard focus.
What you are doing wrong?
I would say what you are doing wrong is trying to access elements inside the DataTemplate from code-behind. Naughty, naughty!
All joking aside, 99.9% of the time I see someone trying to access an element inside a DataTemplate from code, it is because their application is poorly designed, with no (or few) bindings and no view model at all. Many beginners tend to store their data directly in UI elements rather than using a view model. I think it is because their minds have been corrupted by experience VB, WinForms, and ASP.NET where it was the "normal" way to do it. There are a thousand reasons to use a view model and bind your data instead of storing them in UI elements. Look up "model view view model" online for more details.
Now to answer your question:
Any given ListBoxItem can only have one DataTemplate at a time. This is because its ContentPresenter has only one ContentTemplate property, and this property cannot have two different values.
Because of this, the visual tree under a ListBoxItem will always be generated from one a specific template, not a combination of several templates. If you change the ItemTemplate of the ListBox or otherwise update ListBoxItem.ContentTemplate, the visual tree produced by the old template will be thrown away and a new one built.
Let me say that again: If you change data templates, the visual tree produced by the old data template will be thrown away and a new visual tree built.
You can have a hundred data templates defined and usable on a given ListBoxItem, but only one at a time can have a visual tree instantiated for it. And these are the only elements that actually exist as part of the visual tree. All other templates exist only as templates - there are no actual elements created for them.
To put it another way: It is meaningless to ask about how to find elements in two different visual trees instantiated by two different templates on the same control, because a single control cannot have two different templates active at the same time.
Hope this clears things up for you.
Final advice: Do read up on MVVM, and stop trying to access elements inside DataTemplates ASAP. However if you think you might be in that 0.1% who actually do have valid reasons to access elements inside templates, write back with your actual reason for wanting to do so and maybe I can provide further guidance.

WPF Dependency Property question ... need advice on what to do in this particular scenario:

I am attempting to create a sukodu (like crossword) player in WPF, and I realize that I have a whole bunch of controls that will need to know the sudoku grid to function.
Because of this, I think the Sudoku Grid object would be a good candidate to create a dependency property. I am about to start the work, but I have some lingering questions:
Who should own the SudokuGrid dependency property? I am thinking the main window UI element should.
Should I set it as a shared dependency property, where all user controls that represent a part of a sudoku grid simply add themselves to the property via .AddOwner() method?
OR
Set it up as an attached property, defined at the main window, and allow child user controls to set up accordingly?
I don't really want child controls to be allowed to set their own grid property value though, so at this time I am leaning towards shared dependency property, but I am not sure it does what I think it does.
Ultimately what I want is one property where if it's set on a parent UI element, all children UI elements that knows about the property will share the same value, overriding any prior value / setting. Does shared dependency do that?
I know it's a bit long winded, but any help would be much appreciated!
I think what you want is an attached property with the Inherits FrameworkPropertyOption. That we every control that wants to know about the grid can just find the grid by getting the value of the attached property (assuming it is set higher up in the tree). This article goes over attached properties and how to set them up.
Alternativly you might like to try out the Model View View-Model (MVVM) pattern and implement the Sudoku grid as a view-model class which each cell being a ceperate view-model class. That way the whole sudoku puzzel is completly seperate from the UI and the UI can just bind to it using appropriate data templates.
For more info on the MVVM pattern se the following:
http://www.codeproject.com/KB/WPF/MVCtoUnitTestinWPF.aspx
http://blogs.msdn.com/johngossman/archive/2005/10/08/478683.aspx

Resources