I am new on stackoverflow and relatively new to WPF.
I've wrapped my head around a half dozen weighty tomes of Patterns and Best Practices (as well as numerous posts here) but cannot seem to find the solution I am looking for.
My Problem: WPF / .Net 4 / C#
I have a text processor (of type Editor E) that can load one Document (of type Document D) at a time (strored as Editor.CurrentDocument). Several UI controls bind to the Document's properties (all Dependency Properties) such as Document.Title, Document.DateLastModification.
Now I want to be able to switch the actual Document instance without having to unhook and re-hook all event handlers. So I guess the Editor.CurrentDocument property must somehow remain its instance while switching its implementation.
I have tried to create a SingleInstanceDocument class that inherits directly from Document and uses the Singleton pattern. But then I cannot find a way to inject any Document instance into the SingleInstanceDocument without having to internally re-map all properties.
Am I somehow being misguided or missing the point here? If the SingleInstanceDocument approach is a viable solution, is there any way I can use reflection to re-map all available dependency properties from the inner Document to the outer SingleInstanceDocument shell automatically?
Thank you very much!
Addendum:
It turned out that the functionality required here was already provided by WPF/.NET out of the box by implementing INotifyPropertyChanged on the CurrentDocument host object. Thus changing the current document caused the UI to update its bound controls appropriately. I'm sorry for all the confusion.
first, learn some basic MVVM pattern. basically in WPF-MVVM just use ObservableCollection and INotifyPropertyChanged interface.
this type of collection implements the observer pattern that notify update to UI(View) when you add/remove or "select" the current item.
//in main ViewModel
private Ducument _currentDocument;
public Document CurrentDocument
{
get { return _currentDocument; }
set
{
_currentDocument = value;
NotifyPropertyChanged("CurrentDocument");
}
}
//stored all loaded documents as collection.
public ObservableCollection<Document> Documents { get; set; }
binding selected - current item.
<ListBox ItemsSource="{Binding Path=Documents}" SelectedItem="{Binding Path=CurrentDocument}" DisplayMemberPath="Title">
<!-- //all Document.Title as listitem -->
</ListBox>
<!--// Editor's View -->
<ContentControl DataContext="{Binding Path=CurrentDocument}"></ContentControl>
Related
I am completely new to MVVM and I am creating an UWP app for keeping track of my software development, I am still learning.
So what I want to make is:
An app that contains single page ->
In MainPage.xaml I have something like this:
<!--MainPage Content-->
<Grid>
<!--For SearchBox-->
<AutoSuggestBox x:Name="SearchBox"/>
<!--For Adding Item-->
<AppBarButton x:Name="AddAppButton"/>
<!--Listview that contains main data-->
<ListView x:Name="AppsListView"/>
<!--This is DataTemplate of listview-->
<DataTemplate>
<Grid>
<!--Icon of App-->
<Image/>
<!--Name of App-->
<TextBlock/>
<!--For Editing Item-->
<AppBarButton/>
<!--For Deleting Item-->
<AppBarButton/>
</Grid>
</DataTemplate>
</Grid>
In Model I have something like this:
public class DevApp
{
public string name { get; set; } // For App Name
public string Iconsource { get; set; } // For App Icon
public ICommand EditCommand; // For Edit AppBarButton
public ICommand DeleteCommand; // For Delete AppBarButton
}
In ViewModel, something like :
public class ViewModel
{
// For ItemSource of ListView
public ObservableCollection<DevApp> DevApps = new ObservableCollection<DevApp>();
// For Add AppBarButton
public ICommand AddCommand;
}
Now this is me first time trying to create a neat and clean Mvvm app.
Now I have this question:
I know how to bind command to button or AppBarButton but how am I supposed to bind a Methods of a Xaml Control such as Listview's SelectionChanged() or AutoSuggestBox's TextChanged() Methods to ViewModel ?
How can I Load Data from save file ? As there is no InitializeComponent() in ViewModel like in CodeBehind to start from, where shall I pull LoadData() method which loads data to ListView ? ( my viewmodel is bind to view using <MainPage.DataContext> and I wanna keep code behind completely empty. )
Where shall I put Data class that can manage load save and edit data to savefile.
How shall I distribute responsibilities among classes ?
I have seen people using mvvm and they create files like:
services, helpers, contracts, behaviours, etc.
and I have seen same thing in Windows Community Toolkit Sample App
Is it required for Mvvm.
And what are services and helpers.
Shall I really use Mvvm for this ?
I tried using Mvvm in this just for curiosity but like
ITS BEEN 1 MONTH I AM MAKKING THIS APP! but it gets messed up again and again,
If I used Code Behind it would have been done in few days.
BY time now I realize that Mvvm is good at data bind in complex apps but
When it comes to simple things like a simple app with listview, I think code-behind
is better and it keeps things simple.
Please answer these questions I am really struggling in making this app.
I know how to bind command to button or AppBarButton but how am I supposed to bind a Methods of a Xaml Control such as Listview's SelectionChanged() or AutoSuggestBox's TextChanged() Methods to ViewModel
You could bind SelectionChanged with command by using Xaml Behavior InvokeCommandAction, or using x:bind markup extension to bind a method, for more please refer to this link.
How can I Load Data from save file ? As there is no InitializeComponent() in ViewModel like in CodeBehind to start from, where shall I pull LoadData() method which loads data to ListView ? ( my viewmodel is bind to view using <MainPage.DataContext> and I wanna keep code behind completely empty. )
Base on the first question, you could detect Page Loaded event and Invoke CommandAction where in the ViewModel. Then loading the file in the viewmodel LoadedCommand.
<i:Interaction.Behaviors>
<ic:EventTriggerBehavior EventName="Loaded">
<ic:InvokeCommandAction Command="{x:Bind ViewModel.LoadedCommand}" />
</ic:EventTriggerBehavior>
</i:Interaction.Behaviors>
Where shall I put Data class that can manage load save and edit data to savefile
The better place that savefile is current app's local folder, and it have full access permission, please refer to Work with files document.
How shall I distribute responsibilities among classes ?
I have seen people using mvvm and they create files like:
services, helpers, contracts, behaviours, etc.
and I have seen same thing in Windows Community Toolkit Sample App Is it required for Mvvm. And what are services and helpers.
For mvvm design, model view viewmodel are necessary. And it is not necessary to make services, helpers, contracts, behaviours, it should base on your design. For example if you want to make NavigateService, you need make static service class to manager current app's navigation. We suggest you make sample project with TempleStudio that contains some base service and behaviors.
Shall I really use Mvvm for this ?
I tried using Mvvm in this just for curiosity but like
ITS BEEN 1 MONTH I AM MAKKING THIS APP! but it gets messed up again and again,
If I used Code Behind it would have been done in few days. BY time now I realize that Mvvm is good at data bind in complex apps but
When it comes to simple things like a simple app with listview, I think code-behind
is better and it keeps things simple.
Your understanding is correct, But Decoupling(mvvm) your code has many benefits, including:
Enabling an iterative, exploratory coding style. Change that is isolated is less risky and easier to experiment with.
Simplifying unit testing. Code units that are isolated from one another can be tested individually and outside of production environments.
Supporting team collaboration. Decoupled code that adheres to well-designed interfaces can be developed by separate individuals or teams, and integrated later.
Improving maintainability. Fixing bugs in decoupled code is less likely to cause regressions in other code.
In contrast with MVVM, an app with a more conventional "code-behind" structure typically uses data binding for display-only data, and responds to user input by directly handling events exposed by controls. The event handlers are implemented in code-behind files (such as MainPage.xaml.cs), and are often tightly coupled to the controls, typically containing code that manipulates the UI directly. This makes it difficult or impossible to replace a control without having to update the event handling code. With this architecture, code-behind files often accumulate code that isn't directly related to the UI, such as database-access code, which ends up being duplicated and modified for use with other pages.
I'm working on an app that has a "day" and "night" color palette that can change automatically. We're using Xamarin Forms and, for historical reasons, we're not using XAML but I speak XAML so I'm going to use it in this post.
I've approached it by creating a base type with a property for relevant colors like "dark text" or "header background", then implementing that type for both schemes. Then, I made a type that references one of those and raises a PropertyChanged even if it changes. So a day->night transition involves setting the property, then anything in the UI bound to a path like "ColorScheme.DarkText" changes. Nice.
Now I've got a ViewModel that wants to have different colors for some items in a list. I want those colors backed by this day/night change system, but I might have designed myself into a corner. I'll show you what I did and how I want to redesign, but I'm curious if there's a clever way to go about it without causing other problems.
Here's a VM for an item I'm binding to, let's all assume there's nothing unexpected in ViewModelBase:
public class ItemViewModel : ViewModelBase {
public string IconColorName { get...; set...; }
public string IconText { get...; set...; }
}
That ViewModel's contained in another boring ViewModel that makes up the rest of the page:
public class PageViewModel : ViewModelBase {
public ObservableColorScheme ColorScheme { get...; set...; }
public ObservableCollection<ItemViewModel> Items { get...; set...; }
}
OK, so what I'm going for is I'd like XAML for my item's template to look something like:
<StackLayout>
<StackLayout.Children>
<Label TextColor={Binding IconColor, Converter={StaticResource StringToColorConverter} />
...
</StackLayout.Children>
</StackLayout>
Right. OK. So now here's the problem. I can imagine building that IValueConverter and setting it up so it has the same concept of the right color scheme, then using the string value here to get the appropriate property. But I have a problem: there can only be one source for a binding, right? I need the color to change if EITHER the ColorScheme or IconColorName changes. My hunch is WPF could do that, but Xamarin can't?
The most obvious solution I've thought of is some kind of extra ViewModel, in XAML-unfriendly format for brevity:
public class ColorViewModel : ViewModelBase {
public Color Color { get...; set...; }
public ColorViewModel(string colorName, ObservableColorScheme colorScheme) {
colorScheme.PropertyChanged += (s, e) => {
if (e.PropertyName == colorName) {
Color = colorScheme.Get(colorName);
}
}
Color = colorScheme.Get(colorName);
}
}
I do NOT like this. These items are created and destroyed a lot, so that means that event handler needs to be unsubscribed. I don't want to have to think about that, and I can assume a maintenance programmer will forget. I've thought about retooling it to use a WeakReference for the event subscription but... that's getting really icky.
So I'm not really sure how to proceed, short of making the Page here detect color scheme changes and manually update its child views. That feels icky too. I've been thinking about it for a couple of days and nothing nice is presenting itself.
I'm open to "you're doing this terribly wrong, and there's some feature that would make this dramatically easier for you". I'm suspicious that feature is Styles, which I'm not using because 1) the aforementioned lack of using XAML and 2) our project is older than Style support in Xamarin Forms. Feel free to tell me to throw this design away, but please don't do so without showing me a quick example of the better way!
I don’t know xamarin nor C#, so maybe I’ll use the wrong terms, but this is how I would approach this problem:
I assume you have some kind of ViewModel hierarchy and you know the root of this hierarchy.
I would create a ColorScheme class with a static getter of the current color scheme and getters for each color. So you can create a subclass for day and night scheme. Also a void ApplyTo(ViewModelBase). I would create an ViewModelBase interface which has an void UpdateColorScheme() and List Items().
Ok, now, each ViewModel can use the UpdateColorScheme method to setup the view will be created.
Probably there is some kind of event to change the color scheme. This could be a button or a clock based trigger. This event sets the correct ColorScheme and simply calls ColorScheme.CurrentScheme().ApplyTo(rootViewModel). The ApplyTo method walks down the ViewModel hierarchy and calls UpdateColorScheme() for each ViewModel.
This isn’t very fancy but your don’t have to create dozens of objects for something which will change rarely (only twice a day). You only have one instance of ColorScheme and be instance for each Color and a separate method for color settings. But you don’t have to create and register events listeners all the time. The base class will enforce the maintenance programmer to use this concept so he can not forget to setup a event listener and you use the same code for setting up and updating the view.
And a little side note: opinion based questions are not allowed on Stack Overflow. There is a Core Review Page of StackOverflow, I think this question belongs there.
I'm trying to do set a DynamicResource on a content of a Attached Property but this isn't working. Trying to understand why, but I can't figure it out.
Basically, I'm implementing a watermark on a textbox using the code available at: Watermark / hint text / placeholder TextBox in WPF
provided by John Myczek
and using it as so:
<TextBox Text="{Binding SomeProperty}">
<helper:WatermarkService.Watermark>
<TextBlock FontStyle="Italic" Text="{DynamicResource SomeResource}" />
</helper:WatermarkService.Watermark>
</TextBox>
the inner TextBlock works just fine if it is outside the WatermarkService.Watermark attached property. The SomeResource for some reason is empty.
My resources are being loaded as so this.Resources.MergedDictionaries.Add(lastDictionary); since the app is localized and the data is being retrieved from a central place.
Do the controls on the attached properties share the same resources set as their "parents"? What is wrong here?
Thank you
The problem is clear. Dynamic resources are resolved by parsing upwards the logical tree. The dynamic resource is not found because your textblock is not in the correct logical tree, probably he does not have a logical parent and that is why the resource is not found.
You could solve it by adding it to the correct logical tree like for example it could be the child of the textbox. It is not so trivial and depends also on the usage that is required, because the customization of the logical tree is not so trivial.
There is not so simple like having a public method AddLogicalChild because then you would mess up the entire system. Now the question is who has the responsibility of doing this. The general solution could be to have a custom TextBox that overrides logical children related methods and returns also the watermark textblock.
It is not the global solution but in your case you could have a custom textbox overriding the LogicalChildren property like this:
public class WaterTextBox : TextBox
{
protected override IEnumerator LogicalChildren
{
get
{
ArrayList list = new ArrayList();
list.Add(WatermarkService.GetWatermark(this));
return (IEnumerator)list.GetEnumerator();
}
}
}
Remember this is just a workaround and this way would work only on your custom textboxes with dynamic resources.
Also it is not the correct implementation because you should add the watermark to the other logical children not ignore the other logical children and have only the watermark which is not even checked for null like this:
public class WaterTextBox : TextBox
{
protected override IEnumerator LogicalChildren
{
get
{
ArrayList list = new ArrayList();
IEnumerator enumerator = base.LogicalChildren;
while (enumerator.MoveNext())
{
list.Add(enumerator.Current);
}
object watermark = WatermarkService.GetWatermark(this);
if (watermark != null && !list.Contains(watermark))
{
list.Add(WatermarkService.GetWatermark(this));
}
return (IEnumerator)list.GetEnumerator();
}
}
}
To make it more general you should define an interface like IWatermark defining a property like IsWaterMarkAdded which will be implemented by your custom TextBox and ComboBox and will be used by the watermark service. The LogicalChildren override will check for the value of this property. This way you can extend functionality for your TextBox and ComboBox but still it is not an extensible solution for any control.
I am currently trying to design an application that loads viewmodels through MEF imports.
So far so good, I navigate from viewmodel to viewmodel, having loaded each vm datatemplate through dictionaries.
Each time I navigate, I modify the content of the main contentPresenter in my Shell (MainWindow).
One of the viewmodel allows me to display a WindowFormHost for an activeX control (such as acrobat reader for example). Since WindowFormHost does not allow binding, I created the windowFormHost in the viewmodel and binded it to a ContentPresenter in the view.
And here is where it fails : when coming back to the same viewmodel, the view is created again... throwing a “Element is already the child of another element.” error.
How can I prevent that ? Should I unload WindowFormHost when view is reloaded ? Or Can I keep view instances so that I keep only one instance for each view and let data binding update controls ? (It looks better for memory consumption).
Thanks for your help !
[EDIT]
Loaded dictionary :
<DataTemplate x:Shared="False" DataType="{x:Type vm:DAVPDC3DVIAControlViewModel}">
<vw:MyUserControl />
</DataTemplate>
View :
<DockPanel>
<ContentControl Name="WFH3DVia" Content="{Binding Path=Control3DVIA, Mode=OneWay} </ContentControl>"
<!--<WindowsFormsHost Name="WFH3DVia"></WindowsFormsHost>-->
</DockPanel>
VM (singleton, mef module) :
[Export(typeof(IDAVPDC3DVIAControl))]
public partial class DAVPDC3DVIAControlViewModel : ViewModelBase, IViewModel, IPartImportsSatisfiedNotification
VM (main window)
[Export]
public class MainWindowViewModel : ViewModelBase, IPartImportsSatisfiedNotification
// CurrentUC binds main widow view to controller active viewmodel
public IViewModel CurrentUC
{
get
{
return myAddinManager.CurrentVM;
}
}
Main view :
Controler (displays module on event) :
private void ModuleReadyEventAction(string iModuleName)
{
if (null != this.Modules && this.Modules.Count() > 0)
{
foreach (var item in Modules)
{
IBaseModule ibasemodule = item as IBaseModule;
if (null != ibasemodule)
{
Type tp = ibasemodule.GetType();
if (0 == tp.Name.CompareTo(iModuleName))
{
CurrentVM = ibasemodule.GetViewModel();
break;
}
}
}
}
}
I'm also working on a project in WPF using Prism v4 and MVVM (except I'm using Unity). I also have at least two controls that I need to use which are Windows Forms controls that must be hosted in a WindowsFormsHost. Let me explain my thoughts on the process..
It seems to me, that you are trying to avoid any code in your View's code behind. That's the only reason I can think of that you are moving your WindowsFormsHost into your ViewModel. I think that this is fundamentally the wrong approach. The WindowsFormsHost exists for the reason of displaying a graphical Windows Forms control. Therefore, it belongs in the view!
Now, I understand the appeal of DataBindings. Trust me, I've wanted to able to DataBind many parts of my WindowForms control. Of course, to accept a WPF data binding the property must be a dependency property on a dependency object. The easiest solution, which is not unreasonable, is to simply add the code to configure your windows forms control in the code behind for your view. Adding your UI logic into your ViewModel is an actual violation of the MVVM design pattern, while adding code behind is not. (And in some cases is the best approach)
I've seen possible hacks to try to get around this limitation. Including using "proxies" which inject a databinding, or perhaps extending WindowsFormsHost and adding DependencyProperties which wrap a specific hosted control's properties, or writing classes using reflection and trying to throw in windows forms bindings. However, nothing I've seen can solve the problem completely. For example, my windows forms control can contain other graphical components, and those components would need to support binding as well.
The simplest approach is to simply synchronize your view with your viewmodel in your view's code behind. Your view model can keep the file or document that is open, filename, title, etc., but leave the display and display related controls up to the View.
Last, let me comment more directly on your question. I would need to see how you are registering your View and ViewModel with the MEF Container and how you are navigating to understand why you are receiving that error. It would seem to me that either your view or view model is getting created more than once, while the other is not. Are these registered as singleton types? Regardless, I stand by what I said about not including the WindowsFormsHost in your ViewModel.
I'm building a WPF app that connects to a SQL Server database using LINQ to SQL.
The main window of the app contains a ListView containing a series of detail views.
The ItemSource of the ListView is bound to a collection of detail view model objects exposed as a property on the root view model.
Each detail view model object composes several ICommand properties as well as a property exposing a detail model object, which in turn exposes the various data fields shown in the UI.
Analysis with the ANTS memory profiler shows that the objects being leaked are those contained in the detail model object, and some UI classes to which they are bound.
Instances of these objects from previous refreshes are not being garbage collected.
ANTS has a tool that allows the user to trace chains of reference to identify why unwanted memory is being retained. When I use it, I find that all of the chains that show up have an ICommand in them. Accordingly, I've removed the offending ICommand, and found that
the memory leak disappears.
Unfortunately, I need the ICommand to implement some important functionality. What is really confusing me is how it has a reference to the detail model object in the first place- they are two completely separate instance variables in the detail view model object.
Here is the constructor of the detail view model object (The reference to the RootViewModel is used for callbacks in some of the methods connected to the ICommands. I originally suspected that this might be causing a circular chain of references that might be the cause of the problem, but removing it doesn't seem to have any effect.)
public CarDataViewModel(CarData carDataItem, RootViewModel parentViewModel)
{
_parentViewModel = parentViewModel;
CarDataModel = carDataItem;
CompetingCheckboxStatus = CarDataModel.CurrentCar.Competing;
AcknowledgeAlarm = new ParameterlessCommand(AcknowledgeAlarmClicked);
Acknowledge = new ParameterlessCommand(AcknowledgeClicked);
ShowReport = new ParameterlessCommand(ShowReportClicked);
Cancel = new ParameterlessCommand(CancelClicked);
}
Here's the xaml where the bindings are set up - AcknowledgeAlarm is the ICommand, CarDataModel is the detail model object:
<ListView x:Name="itemGridView"Grid.Row="1"ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding CarDataViewModels}" IsSynchronizedWithCurrentItem="True" Margin="0,0,0,0">
<ListView.ItemTemplate>
<DataTemplate>
</DataTemplate.Resources>
<Button Command="{Binding AcknowledgeAlarm}">
<Border DataContext="{Binding CarDataModel}" BorderBrush="{StaticResource GrayFadeBrush}" Background="White" BorderThickness="5">
<Grid> . . .
The CanExecuteChanged event handler is likely implicated in the leak.
WPF expects ICommand implementations to use weak references to the event handlers. You're using a normal .NET event which uses strong references, which can cause this leak.
The way you are creating the ParameterlessCommand instance seems to imply that CanExecute will always be true, and you don't need the event at all.
Are you actually firing the event anywhere, or is OnCanExecuteChanged unused code?
If not, replace the event definition with:
public event EventHandler CanExecuteChanged { add {} remove {} }
This way the event does not store any handlers, and the view model avoids having a strong reference to the UI elements.
If you need to raise the event, the easiest solution is to use CommandManager.RequerySuggested, which matches the weak event semantics expected for ICommand:
public event EventHandler CanExecuteChanged {
add {
CommandManager.RequerySuggested += value;
}
remove {
CommandManager.RequerySuggested -= value;
}
}
Another thing you should do is implement INotifyPropertyChanged in your view model (if you haven't done so already), and use that instead of having individual NameChanged etc. events for each property.
This is because the logic in WPF dealing with the individual properties causes memory leaks when there is a reference from the view model back to the UI elements: http://support.microsoft.com/kb/938416
AFAIK you need to implement INotifyPropertyChanged even if you don't actually have any change events.
My guess is that fixing either of these two problems will make the leak disappear: the incorrectly implemented CanExecuteChanged causes a strong reference from view model to view, which is exactly the circumstance under which the lack of INotifyPropertyChanged causes a leak.
But it's a good idea to fix both issues; not just one of them.