I am trying to achieve something very similar to this:
WPF with Helix toolkit, animate with code-behind?
However, my scenarios is slightly different. I am trying to animate a tube (curve) defined by a path (TubePath) which undergoes deformation as a function of time (animation) defined by a mathematical function (calculated numerically).
My design/plan is to use a usercontrol (containing the Helix Tube control) to draw each frame of the tube defined by a path. I plan to make the TubePath property in my usercontrol which is an oservablecollection a dependency property. I plan to control the animation from my ViewModel (or View) by binding the CurrentPath property of the ViewModel to the usercobtrol TubePath property. I plan to drive my ViewModel from INotifyPropertyChanged. I will a have List of Paths (PathList) stored in advance of starting the animation in my Model. At each (so called) time or animation step, I will copy the corresponding path from the PathList to the CurrentPath in the VieModel. I am hoping that change in the the CurrentPath collection in the ViewModel will activate the binding which will force the user control to update the tube drawn by the usercontrol.
These are my questions:
(1) I have read that not all changes to an ObservableCollection fires propertychanged events. Will overwriting or refereshing the whole CurrentPath collection in the ViewModel update the TubePath in the UserControl which will force redrawing of the tune? Do I have to do anything special to achieve this kind of binding.
(2) I am new to WPF and animations with WPF. My research indicated that I could do the animation from my ViewModel in several ways: using the Dispatcher.Invoke() like in the example given above, or I could use the RenderingEventManager.AddListener() (and RenderingEventManager.RemoveListener() to stop animation) provided by the Helix Toolkit like it is done in example here:
https://github.com/helix-toolkit/helix-toolkit/tree/develop/Source/Examples/WPF/ExampleBrowser/Examples/Wind
or I could loop using DispatcherTimer() as done here:
Binding on DependencyProperty of custom User Control not updating on change
Any suggestions as to the best method as well as my concept of driving animation from the ViewModel would be greatly appreciated.
Related
I'm working on a project that utilizes WPF, using the Prism library and Unity Container.
I have a mainwindow, which contains a mainviewmodel control which in turn is populated by a collection of user controls.
My goal is to set keyboard focus to the mainviewmodel where I have an EventTrigger InvokeCommandAction which reacts to keyeventsargs...
Currently the only way the command is fired if I use a textbox within the control (or child controls). My goal is to have the mainviewmodel control or grid get and preserve keyboard focus.
Any tips would be appreciated!
//Nathan
Either not understanding your question correctly or you should review the basic concepts of MVVM in a WPF implementation.
The View is the WPF controls.
WPF Window/UserControl files contain WPF markup which is the View.
Controls in a view leverage DataBindings to the DataContext property of either the control itself or the parent containing control (which it will inherit).
DataContext property is set to an instance of an object that is the ViewModel. It contains properties to hold values and commands to execute actions.
So conceptually there is no "mainviewmodel control", there is a MainView which contains controls and may in this case have its DataContext property set to an instance o MainViewModel. (hence my confusion)
Finally, while it is possible and some might even recommend writing UI rules/logic in a view model I haven't found much benefit in it.
You are much better off putting UI logic in the XAML or in the MinView code behind. You can still access the MainViewModel in the code behind by casting the MainView.DataContext property as a MainViewModel.
So for example:
MainView.KeyDown event can be wired up to call MainViewModel.CommandX.Execute();
I`m new to WPF and databinding so I stumbled on something.
I have created an app with vb.net where my MainWindow contains controls and a frame in which I load a page.
On the page I have a listview where the data is loaded from the database.
Now, I have created the Viewmodel and set up the properties to bind to the controls on the Mainwindow so I could set IsEnabled property to True or False through the INotifyPropertyChanged.
If I change the properties from the mainwindow code, is working. What I want to be able to do is when I click on an item on the page-listview to change the properties in the viewmodel and reflect it back to the UI of the Mainwindow.
I`v searched and could not find anything to help me out.
Does anyone have a suggestion on how can I achieve this or some directions to the right place where to find useful information or at least what needs to be used so I can research more of it?
Cheers,
If the "Child" viewmodel has a reference to the "Parent" viewmodel it can update the properties on the parent and the INotifyPropertyChanged system should update the UI for you.
I'm not entirely sure this is what you are asking about though, your question is a little unclear.
I'm using MVVM Pattern (with MVVM Light) to build my XAML app (win8). I have a ListView, which is bound to a property of my ViewModel. I also have a button that triggers an operation on that ViewModel, which updates that property (which results in updating the ListView). The button uses commanding to execute the operation on the ViewModel. So far so good.
The problem is that after the list is refreshed I need to perform an operation that strictly belongs to my View, not to the ViewModel. It should scroll the list to a specific item. How to trigger that operation? Should I use a specific ListView event?
Using an EventHandler and the ScrollIntoView(Object) method you can achieve what you want without using references of the View inside the ViewMovel and respecting MVVM pattern.
Create an event in your ViewModel like this:
public event EventHandler ScrollListView;
In your View add a callback to scroll the ListView when the property is updated:
ViewModel vm;
vm.ScrollListView += (sender, e) =>
{
var specificItem = **some item**;
MyListView.SelectedItem = specificItem;
MyListView.UpdateLayout();
MyListView.ScrollIntoView(MyListView.SelectedItem);
};
Then in your ViewModel when you update that property and want to scroll the ListView:
if (this.ScrollListView != null)
{
this.ScrollListView(this, EventArgs.Empty);
}
This is how I usually do with some tweaks for each case of course.
The ViewModel is there to decouple the UI Code from the UI Design (E.g. XAML). [Separation of Concerns of Designer and Developer, Automated testing of UI Code, etc]
Ideally the code-behind file of the View will be empty (except the call to InitializeComponent) and all UI logic and state will be handled by the ViewModel. However, in practice there might be some specific UI manipulation that cannot be handled by data-binding alone and you will need to resort to code. Such code should be placed in the code-behind.
In your case, the logic for (a) when and (b) which item to scroll to must be in the ViewModel (not in the View). Only any additional logic required to perform the actual scrolling in the ListView will be in the View code-behind.
Yes, an event would be the ideal way to do this, to avoid having any references to the View inside the ViewModel. I would recommend however to create a custom event in the ViewModel (e.g. OnFirstItemInViewChanged with arguments the item to scroll to) and in the View code-behind register to this event and just call ListView.ScrollIntoView(item).
Note:
WinForms DataGridView had a property FirstDisplayedScrollingRowIndex. If there was something similar in WPF ListView, you could solve this by binding this property to a ViewModel property, therefore leaving the code-behind completely clean.
I'm kinda new to WPF. I'm making an app using WPF (all the UI controls are already fixed) and MVVM but most of the events are in the code-behind. I'm in the process of clearing the code-behind but I have codes like (the ones below) to switch through tabs, and to trigger visibility of controls depending on parameters:
tabItem1.Selected = true;
textBox1.Visibility = Visibility.Hidden;
lbxHusbandsWives.Items.Add(txtHusbandsWives.Text + '/' +
cbxHusbandsWivesCountry.Text + '/' +
dpHusbandsWives.SelectedDate.Value.ToShortDateString());
How can I do that in the viewmodel? Well, inside a Command? So I can clear the messy code-behind? Thanks for your help. :)
As I said many times before, MVVM doesn't mean "no code behind". There are things that you can or should do in code-behind, as long as they are strictly related to the view and are not necessary for the ViewModel to work properly.
That being said, in most cases you don't need to do anything in code-behind. You normally use bindings to control the view from the ViewModel. This allows the ViewModel to be completely ignorant of the view: it just exposes properties that the view can access, and sends notifications when the values of the properties change. The ViewModel should definitely not manipulate the view or its components.
Everything in the code you posted can be done with bindings in XAML:
textBox1.Visibility can be bound to a bool property of the ViewModel, using a BooleanToVisibilityConverter
lbxHusbandsWives.ItemsSource can be bound to an ObservableCollection in the ViewModel (an ObservableCollection notifies the view when items are added to or removed from it)
txtHusbandsWives.Text, cbxHusbandsWivesCountry.Text and dpHusbandsWives.SelectedDate can also be bound to properties of the appropriate type
I've run into a puzzling limitation in a Silverlight 4 UserControl.
What I'm trying to achieve is to have a panel, which slides out from a minimised state when a button is pressed, but the title bar of it should be draggable with which this maximised state can be resized.
What I've done for the sliding out is to animate the MaxHeight property of the parent Grid of this panel which works quite well even with no hardcoded Height for the panel, but I don't know how can I make this dynamic.
Trying to bind a variable from the code-behind to the 'To' parameter of the 'DoubleAnimation' didn't work, it just silently gets ignored.
As I'm creating UserControls to represent Views, the elements with x:Name properties won't get autogenerated.
I tried to work around this using the code below which mimics what happens in the autogenerated code (with the added bonus of only being done after the layout is actually loaded):
public DoubleAnimation PanelOpenMaxHeightDoubleAnimation;
private void LayoutRoot_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
var LayoutRootreference = sender as Grid;
PanelOpenMaxHeightDoubleAnimation = ((DoubleAnimation)(LayoutRootreference.FindName("PanelOpenMaxHeightDoubleAnimation")));
PanelOpenMaxHeightDoubleAnimation.To = 383;
}
This however breaks when trying to set the value of To, as FindName returns null (I have x:Name manually set in XAML for this particular animation to "PanelOpenMaxHeightDoubleAnimation"). I have the sneaking suspicion FindName can't pick DoubleAnimations up from VisualStates, only actual layout children?
I did find the documentation about XAML Namescopes at http://msdn.microsoft.com/en-us/library/cc189026(v=VS.95).aspx#UserControls, but didn't really understand what my options are from this paragraph (other than being very limited):
For the case of a UserControl, there is no equivalent template part attribute convention for parts of the UserControl in the definition XAML, nor is there a template applied at all. Nevertheless, the namescopes between definition and usage remain disconnected, because the definition namescope is defined and then effectively sealed when you package your UserControl into an assembly for reuse. A best practice here is to define your UserControl such that any value that needs to be set to modify the definition XAML is also exposed as a public property of the UserControl.
What does it mean by the last sentence?
Wondering can I do next? Should I try to generate the entire state from code?
Well, managed to work it out so I'm sharing the solution.
Instead of trying to get a reference to the DoubleAnimation in Resources, I named the Grid in the layout I want to animate and get a reference to that using the code in the original question:
var SlidePanel = ((Grid)(LayoutRootreference.FindName("SlidePanel")));
This does return the element and using that it's possible to create a DoubleAnimation and a Storyboard from scratch purely in code. I just used this code example as a starting point: http://msdn.microsoft.com/en-us/library/cc189069(VS.95).aspx#procedural_code
Best part is, you can change the DoubleAnimation.To parameter even after setting everything up in the Storyboard, so now what I'm doing is just resetting that to my calculated value every time before calling Storyboard.Begin().
It's a bit fiddly to set all these up manually, but at least it works nicely once you do.