I've been tasked with upgrading and rationalising a WPF project built using ModernUI. It references Prism but doesn't actually use it anywhere - almost all code is in code-behind files under the XAML.
This is not testable or maintainable, so I'm implementing viewmodels and working my way through using Prism properly. However, obviously I can't change the look too much and frankly, a visual redesign is not in scope for me, I'm not a graphic designer.
So we're fine, up until we get to navigation. I can't find any reference or even a hint on how to use mui's IContent alongside Prism's Regions.
Can anyone offer a clue?
EDIT:
I still can't seem to get Regions working and thus lose modularity, but I have discovered that I can do navigation in an MVVM way with mui.
If anyone's interested, both MenuLinkGroups and TitleLinks are dependency properties of ModernWindow so it's actually fairly easy to construct them in the viewmodel and bind like this in the Window declaration -
TitleLinks ="{Binding TitleLinks}"
MenuLinkGroups ="{Binding MenuLinkGroups}"
and in the viewmodel -
private LinkGroupCollection _menuLinkGroups = new LinkGroupCollection();
public LinkGroupCollection MenuLinkGroups
{
get => _menuLinkGroups;
set => SetProperty(ref _menuLinkGroups, value);
}
private LinkCollection _titleLinks = new LinkCollection();
public LinkCollection TitleLinks
{
get => _titleLinks;
set => SetProperty(ref _titleLinks, value);
}
I haven't tried this with UserControl yet but I'm fairly convinced it works the same way.
I would still value Regions and thus modules. Any help is appreciated.
Related
I am re-factoring an old winforms project into using MVVM via ReactiveUI. The binding part works great so far except the Grid.Datasource = ReactiveList doesn't seem to give any update on changing/adding/deleting.
I just wanted to confirm here, since the DataGridView.Datasource support databinding list only, ReactiveUI.ReactiveList will not work here? or there could be some possible get arounds.
I've just been struggling with this, the approach I've come up with is to wrap a ReactiveList on the ViewModel with a ReactiveDerivedBindingList.
I've created a BindingSource based on the item ViewModel class for design time support, then I replace this at runtime:
private void CreateDerivedBindings()
{
this.Articles = this.ViewModel.Articles.CreateDerivedBindingList(x => x);
this.ViewModel.Articles.ItemChanged.Subscribe(_ => this.Articles.Reset());
//this.Articles.ChangeTrackingEnabled = true;
this.articlesDataGridView.DataSource = this.Articles;
}
private IReactiveDerivedBindingList<ArticleViewModel> Articles { get; set; }
Subscribing to ItemChanged of the underlying ReactiveList (which has ChangeTrackingEnabled turned on) enables items in the grid to update as they are changed. Setting ChangeTrackingEnabled on the derived binding list didn't do anything. This is a brute force approach, I'd guess causing a full refresh of the grid, maybe there is a more finessed approach.
A simpler approach could be to use a ReactiveBindingList on the ViewModel, but I've not tried this as the class is winforms specific and I'm aiming for a ViewModel which could be reused with WPF.
ReactiveList supports INotifyCollectionChanged, I don't know of any other way that lists can signal they have changed. I could be misinformed about Winforms Grid though!
I'm working on a WPF project that's a mishmash of code-behind xaml/xaml.cs and a few not-quite ViewModels as well.
(Disclaimer: Until recently I've had very little in the way of WPF experience. I can design and lay-out a Window or UserControl fairly proficiently, and I think I get the hang of separating an MVVM ViewModel from the View and doing binding wire-ups, but that's the limit of my experience with WPF at present.)
I've been tasked with adding some new features to the program, such that it looks like converting it to use MVVM properly first is going to be necessary.
I'll demonstrate a specific problem I'm facing:
There is a View called SettingsWindow.xaml that I'm working with. It's a set of textboxes, labels and whatnot. I've stripped-out all of the View data into a ViewModel class which resembles something like this:
class SettingsViewModel : ViewModelBase {
private String _outputDirectory;
public String OutputDirectory {
get { return _outputDirectory; }
set { SetValue( () => this.OutputDirectory, ref _outputDirectory, value) ); }
}
// `SetValue` calls `PropertyChanged` and does other common-tasks.
// Repeat for other properties, like "Int32 Timeout" and "Color FontColor"
}
In the original ViewModel class there were 2 methods: ReadFromRegistry and SaveToRegistry. The ReadFromRegistry method was called by the ViewModel's constructor, and the SaveToRegistry method was called by MainWindow.xaml.cs's code-behind like so:
private void Settings_Click(Object sender, RoutedEventArgs e) {
SettingsViewModel model = new SettingsViewModel(); // loads from registry via constructor
SettingsWindow window = new SettingsWindow();
window.Owner = this;
window.DataContext = model;
if( dialog.ShowDialog() == true ) {
model.SaveToRegistry();
}
}
...but this seems wrong to me. I thought a ViewModel should consist only of an observable data bag for binding purposes, it should not be responsible for self-population or persistence, which is the responsibility of the controller or some other orchestrator.
I've done a few days' worth of reading about MVVM, and none of the articles I've read mention a controller or where the logic for opening child-windows or saving state should go. I've seen some articles that do put that code in the ViewModels, others continue to use code-behind for this, others abstract away everything and use IService-based solutions, which is OTT for me.
Given this is a conversion project where I'll convert each Window/View individually over-time I can't really overhaul it, but where can I go from here? What does a Controller in MVVM look-like, exactly? (My apologies for the vague terminology, it's 3am :) ).
My aim with the refactoring is to separate concerns; testability is not an objective nor would it be implemented.
I personally disagree with putting much in my ViewModels beyond the stuff that is pertinent to the View (it is, after all, a model of a View!)
So I use a Controller paradigm whereby when the View tells the ViewModel to perform some action (via a Command usually) and the ViewModel uses a Command class to perfrom actions, such as saving the data, instantiating new View/Viewmodel pairs etc.
I also actually separate my ViewModel and ViewData (the ViewModel 'contains' the ViewData) so the ViewData is puirely dealing with the data, the ViewModel with some logic and command handling etc.
I wrote about it here
What you need is called Commanding in WPF.
Basically you bind Button.Command to a ICommand property in your ViewModel and when Button is clicked you get a notification in ViewModel without using code behind and casing DataContext or whathever hacks you tried.
http://msdn.microsoft.com/en-us/library/ms752308.aspx
I am a big proponent of the MVVM pattern with Silverlight. Currently I wire the ViewModel up to the View by newwing up the ViewModel in the code behind of the view, thusly:
public partial class SomePage : UserControl
{
public SomePage()
{
InitializeComponent();
// New up a ViewModel and bind to layout root
var vm = new SomeViewModel();
LayoutRoot.DataContext = vm;
}
}
And then all the binding is handled in the View and all the logic is handled in the ViewModel, as the pattern intends.
However, wiring them up this way means that the designer doesn't work well, and I can't use Expression Blend design time data. I know that there are libraries such as MVVM Light that will help to get all this working, but I prefer not to bring in a library, as it is "one more thing" to have to deal with.
Is there a simple pattern for getting MVVM wired up in Silverlight while maintaining designer functionality, especially in Blend? I've done some Googling but there are so many outdated articles out there and so much confusion between WPF and Silverlight and older versions that I have a hard time figuring out which to use.
BTW I'm focused on SL4 with VS2010 if it matters.
There are a few methods you can use.
First, let Expression's Sample Data and design-time attributes (i.e. d:DataContext) take over in the designer. In your code, you would simply condition the view model binding:
if (!DesignerProperties.IsInDesignTool)
{
var vm = new SomeViewModel();
LayoutRoot.DataContext = vm;
}
Second, you can have a special design-time view model that you bind instead:
LayoutRoot.DataContext = DesignerProperties.IsInDesignTool ?
new DesignViewModel() : new MyViewModel();
Finally, another way is to manage the data within the view model. I don't like this because it spreads the responsibility across all view models, but you have more precision:
// constructor
private Widget[] _designData = new[] { new Widget("Test One"), new Widget("Test Two") };
public MyViewModel()
{
if (DesignerProperties.IsInDesignTool)
{
MyCollection = new ObservableCollection<Widget>(_designData);
}
else
{
MyService.Completed += MyServiceCompleted;
MyService.RequestWidgets();
}
}
private void MyServiceCompleted(object sender, AsynchronousEventArgs ae)
{
// load up the collection here
}
Hope that helps!
What you are looking for is "Blendibility". MVVM Light has a concept of the ViewModelLocator and I'm using it on a project with great results.
Here's a great post by Roboblob on the topic. http://blog.roboblob.com/2010/01/17/wiring-up-view-and-viewmodel-in-mvvm-and-silverlight-4-blendability-included/ This post has an example solution so it really helps in the understanding. Rob improves on the MVVM Light implementation and I think does a good job.
I've run into similar issues designing WPF applications. One trick I've learned is to declare an xmlns so you can embed an array of objects in XAML:
xmlns:coll="clr-namespace:System.Collections;assembly=mscorlib"
You can then drop an ArrayList of just about anything into the XAML:
<coll:ArrayList x:Key="questions">
<local:QuestionItem Title="FOO"></local:QuestionItem>
</coll:ArrayList>
You can then set the ItemsSource of a grid, listbox, etc to the array:
<ListBox x:Name="lstStuff" ItemsSource="{StaticResource questions}" />
This technique will allow you to "preview" the look and feel of list-style controls in the designer. It doesn't solve all problems with visual prototyping, but it goes a long way and can be adapted to several different scenarios.
You could, for example, declare your local namespace as an xmlns, then drop mocks of your ViewModel into the Resources of the window or control. I haven't tried this but theoretically you could get a complete design-time preview.
I'm working on a project that is based on an old project someone started and didn't finish. I was trying to use as much of their code as I could, so in doing so I ran into some tweaking issues.
Namely, when I put some of the old xaml in the new project there were some errors that were thrown regarding the "x:static" property and "Dynamic property."
here are the error messages themselves:
Error 1: The type 'DynamicResource' was not
found. Verify that you are not missing
an assembly reference and that all
referenced assemblies have been built.
Error 2: The type 'x:Static' was not found.
Verify that you are not missing an
assembly reference and that all
referenced assemblies have been built.
Some notable points that I think is causing the errors: the old project was programmed in VS2008, WPF, v3.5 .Net framework; whereas I am programming in VS2010, Silverlight 4, .Net framework v4.0.
I realize there are differences from WPF to Silverlight as far as xaml goes and there are plenty of differences from the different .Net framework versions and editions of Visual Studio. But I just can't seem to find a fix for this anywhere so I didn't know if there was just a library I was missing or just something I'm simply overlooking or what.
I can recreate this if need be, but like I said, I'd rather use as much of the old code as I can as long as the tweaking doesn't cause more trouble than what it's worth.
Unfortunately, you can't directly use the DynamicResource and Static keywords in a Silverlight's subset of XAML, but you can mimic their behavior. Here is the article on the topic:
{x:Type} and {x:Static} in Silverlight
In general, there is no easy way to migrate a project from WPF to Silverlight. They have very much in common, but strictly speaking are a different technologies.
Another way to achieve binding to static properties - to bind in code. Below is an example.
Main application class:
public partial class App : Application
{
public static MyViewModel MyViewModel { get; private set; }
// ...
}
Main window markup:
<TextBlock Loaded="MyTextBlockLoaded" />
Main window back-code:
public partial class MainPage : PhoneApplicationPage
{
// ...
private void MyTextBlockLoaded(object sender, RoutedEventArgs e)
{
TextBlock textBlock = ((TextBlock)sender);
if (textBlock.Tag == null)
{
textBlock.Tag = true;
Binding bind = new Binding("MyInfo");
bind.Source = App.MyViewModel;
bind.Mode = BindingMode.OneWay;
textBlock.SetBinding(TextBlock.TextProperty, bind);
}
}
}
Maybe the TextBlock.Tag approach of checking, was Binding already set or not, isn't the most elegant one, but it works.
How would I set focus to a TextBox without specifying the name for that TextBox? At the moment I am doing the following
<Window FocusManager.FocusedElement="{Binding ElementName=Username}">
<Grid>
<TextBox Text="{Binding Username}" Name="Username" />
</Grid>
</Window>
Is there any way of doing this without specifying a Name for the TextBox. As I believe in MVVM having a Name element usually means bad design?
As I believe in MVVM having a Name element usually means bad design?
No, it’s not.
The MVVM pattern is not about eliminating all the code from code-behind files.
It is about separating of concerns and increasing the testability.
View related code like focus handling should remain in the code-behind file of the View. But it would be bad to see application logic or database connection management in the code-behind file of the View.
MVVM examples with code in the code-behind files without violating the MVVM pattern can be found at the WPF Application Framework (WAF) project.
The simple way is to set focus in UserControl_Load event
this.txtBox.Focus();
txtBox.Focusable = true;
Keyboard.Focus(txtBox);
MVVM doesn't mean you can not put code in the code behind file.
In fact, Do not let any pattern restrict you to find the best way of coding.
I have documented a "pure MVVM" way to do this in my answer to a similar problem. The solution involves using Attached Properties and a framework for passing interface commands from the ViewModel back to the View.
Code behind should be avoided when possible, even more when it is in the view. I had the same problem and for simple purposes the best answer is this one as it only modifies the view:
WPF MVVM Default Focus on Textbox and selectAll
If you are looking to set again focus as you interact with other UserControl elements, this will do the trick:
Set focus on textbox in WPF from view model (C#)
I lost 3 days figuring this out, I hope this can help.
As I believe in MVVM having a Name element usually means bad design?
No, it’s not.
According to Microsoft MVP's not only is naming controls is WPF bad practice, it is a quite substantial hit on performance. Just wanted to pass along some words of wisdom
I agree with Sean Du about not letting any pattern totally restrict you, I think performance hit should be avoided whenever possible.
Actually, I found the boolean attached property solution a bit dirty and clumsy in the way that you have to find a twist in order to be sure that the next set of your view model property will really raise the attached property changed event.
A simple and more elegant solution is to bind your behavior on property type for which you can be sure that the next value will always be different from the previous one and thus be sure that your attached property changed event will raise every times.
The most simple type that comes into mind is the int. The solution is then the usual combination of :
The behavior:
public static class TextBoxFocusBehavior
{
public static int GetKeepFocus(DependencyObject obj)
{
return (int)obj.GetValue(KeepFocusProperty);
}
public static void SetKeepFocus(DependencyObject obj, int value)
{
obj.SetValue(KeepFocusProperty, value);
}
// Using a DependencyProperty as the backing store for KeepFocus. This enables animation, styling, binding, etc...
public static readonly DependencyProperty KeepFocusProperty =
DependencyProperty.RegisterAttached("KeepFocus", typeof(int), typeof(TextBoxFocusBehavior), new UIPropertyMetadata(0, OnKeepFocusChanged));
private static void OnKeepFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBox t = d as TextBox;
if (t != null)
{
t.Focus();
}
}
}
The view model property:
public int InputFocus
{
get { return _inputFocus; }
private set
{
_inputFocus = value;
Notify(Npcea.InputFocus);
}
}
The use of the attached behavior:
<TextBox v:TextBoxFocusBehavior.KeepFocus="{Binding InputFocus}"/>
And finaly the use of the property in the VM:
public void YouMethod()
{
//some code logic
InputFocus++;//<= the textbox focus
}
Some REALLY bad minded spirits might say that this logic is bound to the int32 size limitation. Well... I will just choose to ignore them right now ;-)