I have an suite of existing Silverlight applications using the MVVM pattern to separate Views and ViewModels. We use Unity 2.0 for an IoC container to inject dependencies into the ViewModel classes (and supporting types). I have an existing ViewModelLocator class that uses the Unity Container to resolve the ViewModel.
All of this is working great at runtime; however, because the ViewModelLocator relies on the Unity Container being created and configured by a Bootstrapper class that is "Run" from the Application_Start method in App.xaml.cs, I've lost the ability to open the views in the designer or in Blend.
I am looking for suggestions how I can rework the ViewModelLocator to support "Blendability".
Note that I'm not willing to force our ViewModel classes to implement default parameterless constructors just for the sake of Blendability. We also have our ViewModels check the IsInDesignMode property (from the MVVM Light ViewModelBase class) to supply design-time data versus making service calls so we don't have different ViewModel implementations for design-time and run-time.
Let me know what you think.
You want UI elements to have a good design-time experience (including in Blend). That sounds like a reasonable goal.
Let’s look at what a UI element is. For the rest of this answer I’m going to call it a Control. The responsibility of a Control is to render UI and respond to user events. Insofar as it should have behavior, it should only have behavior that relates to UI rendering and user events.
In addition to that, the framework itself (Silverlight as well as WPF) imposes a rule: all Controls must have a default constructor. Furthermore, since the DataContext is a property, it’s optional to assign it.
We should keep encapsulation in mind. Any Control we develop should work nicely within the constraints given above. This means that, apart from having a default constructor, it should also work correctly without a DataContext. In other words, the Blendability experience should be supplied by the Control itself, not any external container that needs to be bootstrapped to assign a DataContext.
When a Control must respond to user events I’ve always found the ICommand interface more than sufficient. Attach ICommands to any applicable event handler in the Control. The ICommands are defined by the View Model, but the beauty of ICommand is that it’s basically a void method which means that it’s trivial to supply a (no-op) Local Default in the case where the DataContext is null. However, that’s rarely necessary, as the Commands aren’t invoked by designers.
Here's an example from my book:
<Window x:Class="Ploeh.Samples.ProductManagement.WpfClient.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Product Management"
Height="300"
Width="300"
MinHeight="300"
MinWidth="300">
<Window.Resources>
<Style x:Key="ProductStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
</Style>
</Window.Resources>
<DockPanel FocusManager.FocusedElement="{Binding ElementName=productsListView}">
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<Separator />
<MenuItem Header="E_xit" Command="{Binding Path=CloseCommand}" />
</MenuItem>
<MenuItem Header="_Actions">
<MenuItem Header="_Refresh" InputGestureText="F5" Command="{Binding Path=RefreshCommand}" />
<MenuItem Header="_Add Product" InputGestureText="Ins" Command="{Binding Path=InsertProductCommand}" />
<MenuItem Header="_Edit Product" InputGestureText="Enter" Command="{Binding Path=EditProductCommand}" />
<MenuItem Header="_Delete Product" InputGestureText="Del" Command="{Binding Path=DeleteProductCommand}" />
</MenuItem>
</Menu>
<ToolBarTray DockPanel.Dock="Top" HorizontalAlignment="Stretch">
<ToolBar HorizontalAlignment="Stretch" HorizontalContentAlignment="Left">
<Button Command="{Binding Path=RefreshCommand}">Refresh</Button>
<Button Command="{Binding Path=InsertProductCommand}">Add</Button>
<Button Command="{Binding Path=EditProductCommand}">Edit</Button>
<Button Command="{Binding Path=DeleteProductCommand}">Delete</Button>
</ToolBar>
</ToolBarTray>
<ListView x:Name="productsListView" ItemContainerStyle="{StaticResource ProductStyle}" ItemsSource="{Binding Path=Products}" SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn Header="Id" DisplayMemberBinding="{Binding Path=Id}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Name}" />
<GridViewColumn Header="Price" DisplayMemberBinding="{Binding Path=UnitPrice}" />
</GridView>
</ListView.View>
</ListView>
</DockPanel>
</Window>
and the code-behind:
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
}
Related
I have a ListView in a dotnet MAUI Windows app with a custom viewcell for the item template. I'd like to control how the focused item is styled. At the moment it becomes grey and has a little blue line on the left edge.
This is the code I am currently using:
<ListView
x:Name="ReportList"
ItemsSource="{Binding Resources}"
SelectedItem="{Binding SelectedResource}"
SeparatorVisibility="None">
<ListView.ItemTemplate>
<DataTemplate x:DataType="vm:ReportItemViewModel">
<ViewCell>
<Grid ColumnDefinitions="*, *, *">
<Label Grid.Column="0" Text="{Binding Name}" />
<Label Grid.Column="1" Text="{Binding Size}" />
<Label Grid.Column="2" Text="{Binding Status}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
On the focused element I'd like to remove the blue line and change the background colour.
I've found some promising looking properties and styles while browsing through the default styles in a PR for the MAUI source code.
These properties include:
FocusVisualMargin
FocusVisualPrimaryBrush
FocusVisualPrimaryThickness
FocusVisualSecondaryBrush
I'm not sure how to use them in my code above, or even if these are available in the current release. Can I set these properties, is this the way to go to get complete control over how the focused item is styled, or is there another way?
I developed one app about months ago with Prism. It's great tool that make perfect structure for my app.
However, today I tried to pick up that app and fix some things that pending for a long time. I used Master Detail page in my app, and today I suddenly found that actually the structure for how I developed this Master Detail page using Prism is kind of out of my knowledge.
So, here it is.
Basically my MasterDetailPage is like this:
<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:b="clr-namespace:Prism.Behaviors;assembly=Prism.Forms"
mc:Ignorable="d"
x:Class="JapaneseLearnPrism.Views.MenuPage">
<MasterDetailPage.Master>
<NavigationPage Title="Menu" Icon="ic_hamburger.png">
<x:Arguments>
<ContentPage Title="{Binding Title}">
<ListView ItemsSource="{Binding MenuItems}"
SelectedItem="{Binding SelectedMenuItem, Mode=TwoWay}"
SeparatorColor="LightGray"
RowHeight="60"
SeparatorVisibility="Default"
BackgroundColor="#e8e8e8">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout VerticalOptions="FillAndExpand"
Orientation="Horizontal"
Padding="20,10,0,10"
Spacing="20">
<Label Text="{Binding PageIconText}" FontFamily="{StaticResource FontAwesomeSolid}" FontSize="Medium" VerticalOptions="Center" />
<Label Text="{Binding Title}" FontSize="Medium" VerticalOptions="Center" TextColor="Black" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Behaviors>
<b:EventToCommandBehavior EventName="ItemTapped" Command="{Binding NavigateCommand}" />
</ListView.Behaviors>
</ListView>
</ContentPage>
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Master>
</MasterDetailPage>
And the navigation path is this in App.xaml.cs file.
await NavigationService.NavigateAsync(nameof(MenuPage) + "/" + nameof(NavigationPage) + "/" + nameof(Views.MainPage));
But if I look at lots of the Xamarin.Forms samples, the MasterDetailPage is actually different.
They are going to do like below:
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MasterDetailPageNavigation;assembly=MasterDetailPageNavigation"
x:Class="MasterDetailPageNavigation.MainPage">
<MasterDetailPage.Master>
<local:MasterPage x:Name="masterPage" />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
<local:ContactsPage />
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
And that's from Microsoft's official website. The Master Page in above is actually just one ContentPage, however, the Detail page should be NavigationPage, that one I can understand because it makes sense.
However, in my Prism app, the MasterPage also has to be a NavigaionPage, why is that? Any one can help on this?
Thanks.
You can take a look at this wonderfull blog about How to make Master-Detail Page Navigation menu in Xamarin Forms with Prism.
If you scroll down to the bottom of the post, you will see some description on why it works this way, Quoting:
Note: Navigation in Prism is all based on this url format where we can define to which pages we want to go, and it can be something like this: ViewA/ViewB/ViewC/ViewD
... and if you remember we are inside of MasterDetail page so navigating from MasterDetail will get result that those pages will go to Detail part of it... and that is great for us, we have menu in side of master page and choosing menu items will open pages as Detail pages.
The way that Prism Navigation is designed, it makes sense that a DetaiPage goes inside the MasterDetail, so basically it keeps the Prism Logic of doing the Navigation.
Quoting the Basics of Prism Navigation
Navigating in a Prism application is conceptually different than standard navigation in Xamarin.Forms. While Xamarin.Forms navigation relies on a Page class instance to navigate, Prism removes all dependencies on Page types to achieve loosely coupled navigation from within a ViewModel. In Prism, the concept of navigating to a View or navigating to a ViewModel does not exist. Instead, you simply navigate to an experience, or a unique identifier, which represents the target view you wish to navigate to in your application.
I want set visible property of MenuItem https://openui5.hana.ondemand.com/explored.html#/sample/sap.m.sample.MenuButton/code/MB.view.xml) component but if I write
<items>
<MenuItem text="Edit" icon="sap-icon://edit" visible="true" />
<MenuItem text="Save" icon="sap-icon://save" visible="false" />
<MenuItem text="Open" icon="sap-icon://open-folder" />
</items>
The result is always all three items visible
EDIT:
release1.40.6 fix the bug
But I want use the last long-term maintenance release (1.38.x)... I don't see the fix here
https://openui5.hana.ondemand.com/#releasenotes.html
This is was a bug of the framework (GitHub issue). The fix is now available as of UI5 1.38.8.
I am using recently released Windows.UI.Interactivity library to wire some events to MVVM commands in a WinRT app. It works fine for ListView, however no event is fired in a ComboBox. Here's a ComboBox control definition (some properties skipped for clarity):
<ComboBox
x:Name="collectionMode"
Margin="10"
SelectedIndex="0">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding CollectionModeCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ComboBoxItem Content="Show collection properties" />
<ComboBoxItem Content="Show collection data" />
</ComboBox>
The CollectionModeCommand is never triggered (I have a similar wiring in a ListView and it works fine).
Any help is appreciated.
Resolved. The problem was with the incorrect binding of the outer control that of course resulted in the CollectionModeCommand not being bound to the ComboBox.
I have a treeview where I can click on items. I am using MVVM light toolkit and the EventToCommand and would like to know which item was chosen. How can I pass this to my viewmodel?
<interact:Interaction.Triggers>
<interact:EventTrigger EventName="SelectedItemChanged">
<cmd:EventToCommand Command="{Binding Path=DataContext.SimpleCommand, RelativeSource={RelativeSource AncestorType={x:Type TreeView}}, Mode=OneWay}"
CommandParameter="{Binding SelectedItems, ElementName=mainTreeView}"
/>
</interact:EventTrigger>
</interact:Interaction.Triggers>
http://www.galasoft.ch/mvvm/#intro With the newest version, you can get the EventArgs of the fired event directly in the ViewModel to handle it.