Linear navigation in WPF MVVM - wpf

I'm using the Cinch MVVM framework, however I think this is something that relates to all WPF approaches.
I want to have a primary screen - Shell or MainWindow - which then contains various viewmodels. To navigate between viewmodels I'm using (or going to use) a tab control styled as a button strip with the content area beneath - which is all ok as I add the viewmodels to the tabcontrol (well to the 'Views' collection which is bound to the tab control) at runtime.
A screen that doesn't fit into this methodology is the sign in screen, which I don't really want to add to the tab control - preferably it should be in it's own usercontrol which takes up the entire screen apart from covering the logo; that is, I would like it to appear in the same window rather than a popup dialog, however I'm not sure how to add/ remove controls dynamically and then add subsequent tabcontrol once the user has signed in successfully (and remove the sign in screen). What containers should be used?
TIA.

The easiest way is put your tabcontrol in a Grid without columns and rows so it fill the grid by default. Then add an extra grid or loginusercontrol to the grid as shown below. The moment a user needs to login you can set the visibility of the MainTabControl" to collapsed and of the LoginGrid to Visible and switch it back after a succesfull login. I hope that the xaml below will help you enough.
<Grid>
<TabControl x:Name="MainTabControl" Visiblity="Visible">
... put your tabs here ...
</TabControl>
<Grid x:Name="LoginGrid" Background="#60FFFFFF" Visibility="Collapsed">
... put your usercontrol to login here or the login controls themself
</Grid>
</Grid>

You could use a ContentControl with content bound to a view model. So you'd have two view-models representing the sign-in screen and the main screen and use DataTemplate to display appropriate screen.
<Window.Resources>
...
<DataTemplate DataType="{x:Type my_view_models:SignInViewModel}">
<my_controls:SignInScreenView />
</DataTemplate>
...
</Window.Resources>
<ContentControl Content={Binding} />

You may be interested by Lakana, it is a lightweight and non intrusive navigation framework for WPF.
Riana

Related

How can I switch Telerik ribbonview elements according to the type of my child viewmodel?

I'm using an MVVM pattern for my WPF application. If the "home" view model, which controls the layout of my application's main window, I have a ChildViewModel property. This holds a viewmodel that can be switched according to what the user is doing. When they select menu items, the child view model switches and the main area of the screen (it's in an Outlook style) switches accordingly.
I do this with a ContentControl and DataTemplate like this: (I'm only showing one of the embeddable views here to keep it short).
<ContentControl Grid.Row="1" Grid.Column="1" Margin="3"
Content="{Binding ChildViewModel}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type vm:VersionsViewModel}">
<Embeddable:VersionsView />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
I also want to add a ribbon to my main window, using the Telerik RadRibbonView control. I want this to have some fixed tabs and buttons that are always visible. In addition, I want to add and remove entire tabs, and buttons within existing tabs, according to the type of child view model. I'd like this to be done in the view in a similar manner to the way I've done the content control, above.
Is this possible? I've tried lots of things but got nowhere so far. I know I could do it by creating a huge "super ribbon" and binding visibility properties but this seems cludgey. I could also have multiple ribbons, each containing the common controls, but this would cause a maintenance problem.
In the end I went with the "super ribbon" approach, as I couldn't find any other way.

Bind border style to current user control

I`m developing a wizard application which has a side menu with 5 borders and a content control that contain application screens (user controls).
The borders styles are suppose to give to user an indication where he is at the wizard steps.
I wrote 2 border styles - the first one is the defult style which applied on all borders by default.
The second one (isFoucusedStyle) need to be applied by the border that suitable to the current screen.
For example when the wizard is showing the first screen: first border need to use the isFoucusedStyle and the others need to use defult style. When the user continues to next screen, the first border need get back to default style and the second border now will apply isFoucusedStyle.
I create the pages instances via xaml at the mainWindow under resources at the next way:
xmlns:view="clr-namespace:App.View"
xmlns:ViewModel="clr-namespace:App.ViewModel"
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModel:OpeningViewModel}">
<view:OpeningView/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:PersonalDataViewModel}">
<view:PersonalDataView/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:BusinessDataViewModel}">
<view:BusinessDataView/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:BusinessDataViewModel}">
<view:BusinessDataView/>
</DataTemplate>
I also have a property - CurrentPage which binded to ContentControl - when the user clicks "next page button" CurrentPage updates and the ContentControl switch UserControl.
There is no any binding between the borders to User Controls, in my current state the borders are just visual graphics without any features.
How can i implement it?
Thanks
I took the "isFoucusedStyle" and config it to baseOn defultstyle.
I added triger to isFoucusedStyle which turns on when Border.Focusable is true.
I Created a converter which has access to current page number.
At every border I bounded focusable property to the converter and sent it "converter parameter" with the suitible page number (page number which represented by current border)
The converter is checking for equility between currentPageNumber to converterParameter and returns boolean result.
The result is turning on (or not) the trigger and set the needed border style.
Thanks anyway.
Firstly I would strongly suggest you base your wizard on the NavigationWindow (or containing a NavigationFrame), this will give you all your back and forwards navigation for free, and if you want you can always re-style your NavigationWindow to match a more wizard like interface (see WPF Wizards). NavigationWindow/Frame also supply you with Navigate() methods that handle the transition between pages.
In order to handle the navigation links (your five side menu items) I bind each link to a View level ICommand which tests to see if we need are already on the correct page in CanExecute. Setting ths borders is then just a case of {Binding CanExecute, Converter={BoolToColorConverter}}.
In your case, you can simply do the same thing. Setup your command to check if we have the right CurrentPage, and Bind as above using a Converter.

How to reuse Menu and Toolbar in different WPF UserControls with adding new buttons?

I'm trying to port current WinForms app to WPF and need help with building WPF class structure.
Currently in WinForms, I have one base class (with Menu, Toolbar, Grid and Context menu) and several inherited classes with different datasources and columns for the grid and additional buttons for menu, toolbar and context menu.
Questions:
What will be the best WPF class structure for my usercontrol to avoid inheritance?
Can I move ToolBar into ResourceDictionary (e.g. ControlTemplate)?
How to add new buttons or to bind commands to existed buttons, if buttons will be specified in a separate resource file?
Any other ideas?
Due to inheritance restrictions in WPF I see only one way to avoid duplicating Menu, Toolbar, etc. - implement base class in C# code only without XAML. And likely I can't use XAML for inherited classes as well (have no idea how to add new buttons in XAML into Toolbar created in base class)
In WPF a Toolbar is an ItemsControl (same for Menu), so it has an ItemsSource property you can bind to your collection of toolbar items.
<Window.Resources>
<DataTemplate x:Key="ItemTemplate1">
<StackPanel>
<TextBlock Text="{Binding Property1}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid x:Name="LayoutRoot" DataContext="{Binding MyViewModel}">
<ToolBar HorizontalAlignment="Left" VerticalAlignment="Top" ItemTemplate="{DynamicResource ItemTemplate1}" ItemsSource="{Binding ToolbarItems}"/>
</Grid>
In this code, ToolbarItems is an ObservableCollection< MyToolBarItem >, where MyToolbarItem is a viewmodel that represents one toolbar item.
MyToolBarItem could be the base class, with several classes inheriting from it. Then you can use a DataTemplateSelector to use a different template depending on the type of toolbar item it is.
In this way, all your user controls that have a toolbar can use the same templates you define in your dictionary; each toolbar is just bound to a different collection of MyToolBarItems.
If some of that sounds overwhelming, you can read up on some MVVM. It is the design pattern that makes WPF great.

MVVM Command without A Button

I want to initiate a bound command, but I don't want to use a Button on my UserControl. In effect the UserControl is itself a Button. When it is clicked anywhere on its surface I want to initiate a bound command. Is there a way to give a UserControl a command?
In a side note: one command for one control and only a few certain out-of-the-box controls? This all seems a little clunky. I'm starting to think that MVVM is impractical. I can decouple my UI just fine with Interfaces and OOP. Anyway, I still have hope.
Also, I'm not willing to hack anything or use an expensive workaround. If I can't do this, I'm abandoning MVVM.
Take a look at the ICommandSource interface here: http://msdn.microsoft.com/en-us/library/system.windows.input.icommandsource.aspx. If you want a control to have a command, then your control should implement this interface. Examples of controls that implement this interface are ButtonBase and MenuItem. Hope this helps.
If your UserControl is essentially a Button, why are you writing your own UserControl instead of using the Button class?
To add more info, here's what you do:
Subclass Button, put any extra DependencyProperties that you need in there - it should be a very empty class (you could even have something like public class MyCoolButton : Button { }
Add a Style whose TargetType is MyCoolButton - don't name the style so it applies to all MyCoolButtons
Override the default Template of the style, then paste in your Xaml code. You might have to do some work here to handle the "Normal / Pushed / Disabled" states. If you're using v4.0, you can use VSM here.
I will agree with Paul Betts.
Quite often I create my own ListBoxItemContainerStyle using a button as the top container with nothing but a propertyless content presenter in it. This allows me to use the buttons functionality (like Command) without having the Windows chrome on it.
Putting it in the ListBoxItemContainerStyle also lets me make it so that when it is clicked it does not display the normal dotted border (FocusVisualStyle={x:Null}).
Are you using Visual Studio or Expression Blend to do your styling?
Additionally, some MVVM frameworks provide an interface for adding a command-ish ability to controls other than buttons. Caliburn has a pretty rich command pattern. I am not sure if it allows binding commands on non-button controls, however.
The OP asked for an example of how you could use a button control, but with the content properly filling the entire button. You can do this using the ContentAlignment properties:
<Button HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<Button.Content>
<Grid IsHitTestVisible="False">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Row0" />
<TextBlock Grid.Row="1" Text="Row1" />
</Grid>
</Button.Content>
</Button>
This creates a button with two labels spaced using a Grid control. I mark the Grid to turn off HitTestVisible, as you have to decide which controls should interact like the button and which should interact like controls. For instance, you might have an embedded TextBox that you want to be clickable without clicking the button, in which case it should have HitTestVisible=True.
WPF supports layers and transparency :
Panel.ZIndex
You can create anything that supports commanding on a superior transparent layer, the size you want, to act as a button.

Best practice for dynamically adding controls through copying existent controls in WPF

I have a TabControl.
While clicking a button I want to add a new TabItems to the TabControl.
Among various techniques I've chosen to create UserControl inside of a DockPanel.
Everything works fine, except for the location of control on a new TabItem is not 0 and it is
not expanded on the main form resize.
Everything is quite simple.
<TabItem Header="new control">
<DockPanel LastChildFill="True">
<tc:TabItemTemplate/>
</DockPanel>
</TabItem>
And TabItemTemplate is also located inside a DockPanel, but it's not docked inside a TabItem. What's the catch?
I would suggest using TabControl.ItemTemplate, and bind TabControl.ItemsSource to ObservableCollection of ViewModels. When user clicks on a button, add new View Model instance to the collection. Refer to this article for more details: WPF Apps With The Model-View-ViewModel Design Pattern

Resources