DataTemplate DataType, no class, just xaml - c#

So I'm trying to understand some code we have on a project that is in C#/WPF. I'm pretty new and just learning whatever I can. Looking at one of the .xaml, we have a DataTemplate that lays out where things go for our app. I want to add some events to it, but there is no code behind the .xaml since it is not a class like other .xamls in our project. The DataType of the DataTemplate points to a ViewModel class, but this class does not see my objects in the DataTemplate. Any thoughts? Thanks.

To add rich event-based behavior to elements created through XAML, you need to utilize attached behaviors.

In addition to the attached behaviors John mentioned above, if you are using MVVM, you can utilize the commanding architecture in WPF. Check out ICommand and implementing those on your ViewModel. You will have something like this:
Command="{Binding YourCommandName}"

Related

Is manipulating view objects from view models a standard in Prism projects?

I have very little experience with Prism and .NET (< 1 year). Yet, I am working on a project where those technologies are used extensively. Also, I am an experienced developer, but in other frameworks, other programming languages, etc. Therefore, I have sometimes stupid questions to ask like the following one.
So, we are currently trying to build up a client application that shows a grid of data along with buttons allowing for the usual CRUD operations. The team's ansatz is the following:
We create a xaml view and define the GridControl like this:
<dxg:GridControl x:Name="MyGrid"
ItemsSource="{Binding Items}"
SelectedItems="{Binding SelectedItems}">
<dxmvvm:Interaction.Behaviors>
<dxmvvm:EventToCommand EventName="Loaded"
Command="{Binding GridLoadedCommand}"
CommandParameter="{Binding ElementName=MyGrid}" />
</dxmvvm:Interaction.Behaviors>
[...]
This triggers command GridLoadedCommand upon view loading. GridLoadedCommand stores the GridControl object in the view's data context, which is the view model.
Upon clicking the DeleteAll button, the view model's DeleteAllCommand calls a method of the following kind:
public static void DeleteAllRows(GridControl gridControl)
{
gridControl?.SelectAll();
DeleteSelectedRowsEx(gridControl);
}
In essence, that is perfectly valid code and is also working like a charm. However, in my opinion, but I might be mistaken, that kind of code goes against MVVM philosophy because in the above snippet we are clearly mixing up "view" with "view model" code. Indeed, the view model manipulates a GridControl object directly, which, as far as I know, should be avoided as much as possible, as it breaks "separation of concerns" and makes the software design entangled. Also, it might complicate unit testing a bit. Am I seeing that right or am I alien here? I would rather manipulate the ViewModel.Items and ViewModel.SelectedItems observable collections directly and trigger the relevant events to update the view instead.
Now, the actual reason why the team came up with that code is because they wanted a generic base view model class with generic CRUD operations, irrespective of what the underlying ItemsSource abd SelectedItems (see GridControl xaml code above) are. Is there a standard way to make that happen in the Prism constellation? I would just add a generic parameter to the base class with the ItemsSource's data type and pass the specific ItemsSource and SelectedItems to the generic class. Is there a better way? Is the way I've described here above with direct GridControl manipulation from the view model really the way to go?

Access DataContext of Page from MainWindow (with Telerik)

I am relatively new to WPF and I have stumbled across a problem that I just can't seem to find a solution for.
I am sure that there is already a thread concerning a problem like that but in regard of my lacking knowledge it is very likely that I haven't found it or simply did not understand it.
My problem:
I am developing a WPF-application in C#. It's an Outlook-Styled application with a big MainWindow with a huge ViewModel and XAML.
What I was trying to do, is to split up the single codefiles a bit to make it a little bit more modular and compact.
I am using Telerik Controls and tried to outsource the content of single SplitContainers into Pages, which worked fine until now.
Today, a new situation came up which is somehow stupid and wasn't looking too complicated, but somehow I can't get it to work.
Situation:
I have a Treeview in my "MainWindow" and whenever I change the selection in there, I want to change a property on my Page that I have made a binding to.
So, when I click on an item in "TreeView_3" I want to set a property via EventHandler (SelectionChanged_TreeView3) on the DataContext of "Page_X".
If I had to do this on the MainWindow, I would typically do it like that:
UserViewModel uvm = mainGrid.DataContext as UserViewModel;
Then just call whatever property of specific UserViewModel (ViewModel of the MainWindow) I want to access.
I can't do this the same the same way for the page obviously since "mainGrid.DataContext" will always refer to the MainWindow, since this is where the eventhandler is called.
So what I need would be a little explanation on how to access the DataContext from a page with a different ViewModel.
If you need any code in order to explain, let me know.
You need to separate your concerns. In your code behind your should have only code that handles view related stuff. Most often my codebehind is empty.
In your ViewModels you should handle your data related logic. So instead of casting the datacontext in your code behind, handle a click with a Commandin your viewmodel.
Since there is no possibility to bind a command to the SelectedItemChanged of your TreeView you can use an interaction trigger.
<TreeView xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<i:InvokeCommandAction Command="{Binding Path=SomeCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
Ruven it is hard to say without some example code. But it could be that you need to implement INotifyPropertyChanged on the ViewModels?
https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-implement-property-change-notification
By calling OnPropertyChanged("PropertyName"); in the setter of a viewmodel property the ui will pick up the change.
Also make sure both views are referencing the same object and not copies of the same object.

MVVM Displayer OberservableCollection<ViewModel> with unknown UserControl

im a little bit stuck with my current project and hope someone can help me out of this.
My application works with plugins so that the user is able to add additional functionality to the application. Now i would like to have the configuration window in the same style (Maybe a plugin need some kind of configurations).
The configuration window loads all plugins and get the configuration ViewModel from the plugins. All the ViewModels are stored in an ObservableCollection. These ViewModels should be displayed in a TabControl (one tab per ViewModel)
But i dont know the type of UserControl the plugin is using, because the plugin come up with its own UserControl for configuration purposes.
Otherwise i would create a TabControl, bind its ItemsSource to the ObservableCollection and specify the UserControl in the Resources (DataTemplates).
But how to do it in case the UserControls are unknown to compile time?
I thought about using a ObservableCollection instead of ViewModels, but im not realy happy with that and even dont know if this will work.
Do you have some idea how to deal with that?
Kind regards,
SyLuS
You could use a ContentControl to achieve this.
It's used to show views depending on their viewmodel.
In your xaml you can specifiy which view should be shown. Based on the viewmodel which is the current DataContext.
<ContentControl>
<ContentControl.Resources>
<DataTemplate DataType="{x:Type vm:MyViewModel}">
<v:MyView/>
</DataTemplate>
</<ContentControl.Resources>
</ContentControl>
But when you say you are using a plugin system, maybe something like PRISM, you have to setup the datatemplates automatically. Never done this before. But maybe I gave you a point where you can start.

Databound windows phone panorama with MVVM design

Please assist with MVVM design/understanding problem.
Given that we have a Windows Phone app with following UI structure:
MainPage.xaml body:
<views:PanoramaView/>
DataContext is set via MVVM Light view-model locator to a static MainViewModel class instance.
Views/PanoramaView.xaml body:
<UserControl.DataContext>
<ViewModels:PanoramaViewModel/>
</UserControl.DataContext>
<StackPanel x:Name="LayoutRoot">
<controls:Panorama Background="{Binding PanoramaBackgroundBrush}"
ItemsSource="{Binding PanoramaItems}"
ItemTemplate="{StaticResource panoramaItemTemplate}"
/>
</StackPanel>
At that point I have stumbled upon a question - What should I do in case I want all my PanoramaItems to be comprised of a different user controls? If I define a panorama item template, I doom all of them to be alike. But my intention is to have serveral, compeltely different panorama items. I wanted to have a class (presumably PanoramaViewModel) that would allow me control which panorama items are displayed at a given moment of time.
So there has to be a way for me to still stick to MVVM, but to be able to instantiate new Views(Panorama Items) and inject them into a PanoramaItems collection of my PanoramaViewModel. Where and how do I do that?
You have to define resource key to define a data template with view setter for the view item being rendered for the different view model class types, and derive VM classes from a common base class (PanoramaViewModel, i.e)
In WPF I should have use a DataTemplateSelector to work around my design problem.
Since Windows Phone apps are more like Silverlight, I can implement it myself. A good example of how is in this article and this silverlight.net forum thread.

Binding a method to a column in datagrid WPF

I have a data grid in wpf which is bound to Collection. In one of the columns i want to bind a public method which returns string instead of a property.
Is there a way to resolve this in WPF.
By the way its one way binding.
I'm not entirely sure what you want to do and the advice of the previous two answers may be (and probably are more) appropriate in your scenario but just you answer your question, you can indirectly bind to a method using an ObjectDataProvider.
<Window>
<Window.Resources>
<ObjectDataProvider x:Key="newGuidProvider"
ObjectType="{x:Type Guid}"
MethodName="NewGuid"
/>
</Window.Resources>
...
<TextBlock Text="{Binding Source={StaticResource newGuidProvider}" ... />
...
</Window>
This is just a quick example and you can look into the ObjectDataProvider to see if it's right in your scenario. Here is a great resource which shows additional possibilities such as passing parameters to a method etc., via bindings.
You may be able to accomplish this by using
some evil tricks
an IValueConverter
an attached property
a behavior
by creating a read only proxy property.
However I'll would recommend using a property. It's the way WPF is supposed to work and handles all UI updating logic for you, too.
Why do you want to bind to a method?
If I right understand what you want, it should be enough to you to implement IValueConverter interface and assign it in XAML to you columns data binding's Converter attribute: here is an example how to use it: WPF Converter Example
for more detailed analysis can have a look on SvnRadar opensource project that use a bunch of them.
EDIT
There is no DataGrid control actually, there is a ListView, but the consept is the same.
Hope this helps.

Categories