how to make a viewmodel singleton instance? - c#

The idea is to do this. I have a login page that has successfully passed the Username.text value into a text box in the main window.
Now I need this username.text value in the main window to be passed on to textboxes in all child pages. I am doing this so that the program will know which user is logging in and can log who is making what changes to the database.
One-way Databinging from what i know is the best way of doing this but, i understand i need to create a viewmodel singleton instance for it to work between the MainWindow, and the child pages.
this is what I am failing to do. this code works fine in the same page.
<TextBox x:Name="username" Text="{Binding Text, ElementName=alias, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" Height="19" VerticalAlignment="Top" HorizontalAlignment="Left" Width="211" FontSize="11"/>
<TextBox x:Name="alias" Margin="186,64,0,0" Height="18" VerticalAlignment="Top" HorizontalAlignment="Left" Width="211" FontSize="11" ></TextBox>
in different pages though, nothing.
Code for MainWindow
<mui:ModernWindow x:Class="Masca.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
Title="Masca Database Admin" Height="800" Width="1280" IsTitleVisible="True"
LogoData="F1 M 24.9015,43.0378L 25.0963,43.4298C 26.1685,49.5853 31.5377,54.2651 38,54.2651C 44.4623,54.2651 49.8315,49.5854 50.9037,43.4299L 51.0985,43.0379C 51.0985,40.7643 52.6921,39.2955 54.9656,39.2955C 56.9428,39.2955 58.1863,41.1792 58.5833,43.0379C 57.6384,52.7654 47.9756,61.75 38,61.75C 28.0244,61.75 18.3616,52.7654 17.4167,43.0378C 17.8137,41.1792 19.0572,39.2954 21.0344,39.2954C 23.3079,39.2954 24.9015,40.7643 24.9015,43.0378 Z M 26.7727,20.5833C 29.8731,20.5833 32.3864,23.0966 32.3864,26.197C 32.3864,29.2973 29.8731,31.8106 26.7727,31.8106C 23.6724,31.8106 21.1591,29.2973 21.1591,26.197C 21.1591,23.0966 23.6724,20.5833 26.7727,20.5833 Z M 49.2273,20.5833C 52.3276,20.5833 54.8409,23.0966 54.8409,26.197C 54.8409,29.2973 52.3276,31.8106 49.2273,31.8106C 46.127,31.8106 43.6136,29.2973 43.6136,26.197C 43.6136,23.0966 46.127,20.5833 49.2273,20.5833 Z"
ContentSource="/Pages/Home.xaml">
<Window.DataContext>
<TextBox x:Name="username" Text="{Binding Text, ElementName=alias, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" Height="19" VerticalAlignment="Top" HorizontalAlignment="Left" Width="211" FontSize="11"/>
Code for child page
<UserControl x:Class="Masca.Mail.Configuration"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="1280">
<TextBox x:Name="alias" Margin="186,64,0,0" Height="18" VerticalAlignment="Top" HorizontalAlignment="Left" Width="211" FontSize="11" ></TextBox>
Anyone know how to do this?

I recommend you to use the Cinch MVVM framework that uses MEF to instantiate / inject ViewModels. Making a Singleton ViewModel is really easy using the proper export attribute.
Check the site of the project. I encourage you to use it.
http://cinch.codeplex.com/

If you are using MVVM and the goal is to share data between viewmodels, what you need is a Mediator/EventAggregator. Your MainViewModel can post data onto Mediator once the login is successful, and all other ViewModel can listen for this message and update their corresponding properties for UserName.
More reading on these:
EventAggregator: http://blogs.u2u.be/diederik/post/2011/01/15/Using-the-Prism-40-Event-Aggregator.aspx
Mediator: http://marlongrech.wordpress.com/2009/04/16/mediator-v2-for-mvvm-wpf-and-silverlight-applications/
However, if you really want to make your ViewModel a singleton and have that as DataContext for all views, you want to read this MSDN page about implementing Singleton in C#.

Related

Calibrun.Micro Sample/Feature/UWP : What is "cm:Bind.Model="{Binding}"

Here is Calibrun.Micro example with UWP.
in Bubbling sample, in this file,
there is this line
<Grid cm:Bind.Model="{Binding}">
What is mean ? Why does it necessary ?
I thought Next line is enough for send $dataContext
<Button x:Name="Message" cm:Message.Attach="SelectPhrase($dataContext)" Margin="0,12" />
Please advice me....
Let's analyze the code as quite some things are a bit obscure in Caliburn.Micro as it works through convention:
<Page
x:Class="Features.CrossPlatform.Views.BubblingView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:cm="using:Caliburn.Micro"
mc:Ignorable="d">
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="actions" Style="{StaticResource SubheaderTextBlockStyle}" Margin="40,10,40,0"/>
<StackPanel Margin="40,20">
<ItemsControl x:Name="Phrases">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid cm:Bind.Model="{Binding}">
<Button x:Name="Message" cm:Message.Attach="SelectPhrase($dataContext)" Margin="0,12" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</StackPanel>
</Page>
First of all, the page's datacontext (viewmodel) is set through naming convetion. This viewmodel can be found here. As you can see, this viewmodel has a Phrases property and a SelectPhrase(MessageActivityViewModel phrase) method.
If we go down the tree, we have an <ItemsControl x:Name="Phrases"> which binds to the Phrases property, which is a collection of MessageActivityViewModel.
An ItemsControl needs a way to present the items, which is defined in the DataTemplate. This template has a Grid as root object. If the Grid would not use {Binding}, it would inherit the datacontext from the template, which is the current element being rendered (a single MessageActivityViewModel). However, we want to call the SelectPhrase method on the BubblingViewModel and not on the MessageActivityViewModel. To be able to do that, we use {Binding} to tell the Grid binds to the page's viewmodel instead of to the single rendered MessageActivityViewModel.
What the Button does, is sending the datacontext object (being the rendered MessageActivityViewModel item) back to your viewmodel.
$dataContext:
Passes the DataContext of the element that the ActionMessage is attached to. This is very useful in Master/Detail scenarios where the ActionMessage may bubble to a parent VM but needs to carry with it the child instance to be acted upon.
Source: http://caliburnmicro.com/documentation/cheat-sheet

Bind object's children to TextBox

I using Entity Framework to manage my connection to the DB.
I have this example object:
Company
UniqueCode
Name
Address
I'll search the database using the UniqueCode to find a Company and after finding one, I want to show Name and Address on a couple of TextBoxes.
The example Xml is this one:
<TextBox x:CodeTextBox ...>
<Grid x:Name="ValuesGrid">
<TextBox x:Name="NameTextBox" ...>
<TextBox x:Name="AddressTextBox" ...>
</Grid>
And later, if the user modifies anything, I'll save the values to the DB.
So, what's the best way to show values of an object in a bunch of TextBoxes?
I'm thinking about using DataContext on the ValuesGrid, but I don't know how to make it work.
<Grid x:Name="ValuesGrid" DataContext="{Binding Company}">
<TextBox x:Name="NameTextBox" Text="{Binding Name}">
<TextBox x:Name="AddressTextBox" Text="{Binding Address}">
</Grid>
Where Company needs to be non-private property.

Using Icons in WPF Database Driven Application Results

I am attempting to make a WPF application. The application needs to use a "list view" to show results of queries to the database. I have been able to successfully create the application (GUI, database, LINQ, etc.), however, the display of my query results appear more "gridlike".
The specifications for the project below show that each record that appears in the results needs to have a green circle icon next to it. I have removed the actual results from the images below to keep the contents of the database private.
I don't have enough Reputation Points to post images, so I posted pictures so a sample/testing domain that I use. You can see screenshots here of the WPF app and code here:
http://digitalworkzone.com/WPF.html
What am I doing incorrectly? Is there something I need to add or modify to my code to be able to get the green circles and more of a "list" style to display my query results?
Understand the WPF content model. http://msdn.microsoft.com/en-us/library/bb613548.aspx
Anything that has a 'Content' property basically behaves in two ways. If the 'Content' is set to something that derives from UIElement, then the class will manage it's own presentation. Anything else, however, will just get .ToString() called, and it's text displayed instead.
What this means in the long run is that everything in WPF can display anything. If you want to show a button in a button, you can. For example:
<Button>
<Button.Content>
<Button Content="This will show as text" />
</Button.Content>
</Button>
The inner button will have text, but the outer button will show a Button because Button derives from UIElement and therefore will handle its own presentation.
In your picture examples above, you have ListBoxes/DataGrids that you want to fill in with graphical information. Try this out:
<ListBox HorizontalContentAlignment="Stretch">
<ListBox.Items>
<Button Content="One"/>
<Button Content="Two"/>
<Button Content="Three"/>
<Button Content="Four"/>
</ListBox.Items>
</ListBox>
Now you have a ListBox that shows Buttons instead of Text. You can take this a step further and contain the items in a stackpanel, for example:
<ListBox HorizontalContentAlignment="Stretch">
<ListBox.Items>
<StackPanel Orientation="Horizontal">
<Button Content="A button"/>
<Label Content="Some text" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button Content="A button"/>
<Label Content="Some text" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button Content="A button"/>
<Label Content="Some text" />
</StackPanel>
</ListBox.Items>
</ListBox>
Now we have items that contain a layout container (StackPanels, which then contains other elements).
However, if you set the ItemsSource elsewhere, you can actually use a DataTemplate to display the contents. A DataTemplate in effect targets a particular class and lays out it's contents as defined in XAML. Consider:
Code Behind:
public partial class MyWindow : UserControl {
public MyWindow() {
InitializeComponent();
MyListBox.ItemsSource = new List<Person> {
new Person("Sam", "Smith"),
new Person("Jim", "Henson"),
new Person("Betty", "White"),
};
}
XAML:
<ListBox HorizontalContentAlignment="Stretch" x:Name="MyListBox" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Label Content="{Binding FirstName}"/>
<Label Content="{Binding LastName}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now when the Listbox displays, it will cycle through each of the items in the ItemsSource property, and then lay them out using the DataTemplate. It's possible to have the DataTemplate target specific classes by using the DataType property if you're using polymorphism (as in different types of people such as 'Cusomters' or 'Employees' which all derive from 'Person).
The problem with this approach is that you are setting the value of the items directly, which is bad form. It's better to define a class that handles all of the data for your view separately. Consider:
public class ViewModel {
// WPF will automatically read these properties using reflection.
public List<Person> People {
get {
return new List<Person> {
new Person("Sam", "Smith"),
new Person("Jim", "Henson"),
new Person("Betty", "White")
};
}
}
}
That will hold all the data for the view, now let's add it to the actual window. First we need to reference the namespace ('xmlns' means xml namespace):
<Window x:Class="Sharp.MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:lol="clr-namespace:Sharp">
The namespace is Sharp (the namespace where my stuff lives), and the alias we'll give it is lol. Now we attach our ViewModel class to the window by setting it to the DataContext property, as in:
<Window>
<Window.DataContext>
<lol:ViewModel />
</Window.DataContext>
</Window>
This makes all of the public properties on the ViewModel class available to the Window. This way, if we want to read the Persons information into our ListBox, we simply say:
<ListBox HorizontalContentAlignment="Stretch" ItemsSource="{Binding People}" >
...
</ListBox>
Notice that we say ItemsSource={Binding People}, which means 'scan the ViewModel for any public properties called 'People' and then retrieve those results. This is essentially the fundamentals behind the MVVM approach. You might have all of your business logic in one or many classes which handle the main application operation in a Model, but then you have a ViewModel which interacts with the Model and exposes the results as public properties. WPF automatically binds to those properties and presents them for your. The information just flows, rather than setting the values by force.
To really understand how WPF is supposed to work, you should take some time to understand the basics of MVVM. WPF was really designed with MVVM in mind, and so to really get how WPF is supposed to work, you really should take the time to get your head around it. Take a look at:
http://agilewarrior.wordpress.com/2011/01/11/simple-mvvm-walkthrough-part-i/ .
<ListBox ItemsSource="{Binding QueryResults}">
<ListBox.ItemsTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageSource}"/>
<TextBlock Text="{Binding TextSource}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemsTemplate>
</ListBox>
Will work if you have a list of objects named QueryResults in your code behind. Each object needs to have an string property named ImageSource and a string property named TextSource.
However, since you only need to display a green circle icon for each of the items, you can hardcode the image source. The above will work if you want to have a different icon for each, though.
Also note that in order for this to work, you need to set the DataContext of the window to DataContext="{Binding RelativeSource={RelativeSource Self}}"

Why a simple textblock app runs and a simple app with a button fails in WPF

Folks, I am seeing that the below code gives runtime error when I paste it in notepad and save as test.xaml and run it.
<Page xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBlock Text="Hi Ramakrishnan, good morning"/>
<Button x:Name=”blueButton”
Width=”100”
Height=”40”
Background=”Blue”
Content=”Click Me” />
</Page>
But the below code doesn't give any error but displays the textblock content very correctly in the browser. Any thoughts ? I have also checked including a textbox in place of button above, still same error.
<Page xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBlock Text="Hi Ramakrishnan, good morning"/>
</Page>
You need to wrap your TextBlock/Button in a StackPanel or other control that allows multiple controls in it's content.
<StackPanel Orientation="Horizontal">
<TextBlock Text="Hi Ramakrishnan, good morning"/>
<Button x:Name="blueButton"
Width="100"
Height="40"
Background="Blue"
Content="Click Me" />
</StackPanel>
Your pasted code is using "smart quotes" instead of "normal quotes" on the button.
<TextBlock Text="Hi Ramakrishnan, good morning"/> <-- normal quotes
<Button x:Name=”blueButton” <-- smart quotes
Have you edited or saved or pasted this through MSWord, perhaps?
(If this isn't the problem then it's possible that what you've pasted in your question isn't exactly what you have in your Xaml file, in which case you should update your question...)

WPF Design question

Lets say i am developing a chat, first you come to a login window and when your logged in i want to use the same window but chaning the control :P how would be the best way to desight this?
is there any good way to implement this what root element should i use?
Thanks a lot!!
Take a look at Josh Smith's article in MSDN magazine (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx). He describes an interesting method where you have a content presenter on your main window use data templates to switch out what the window is showing.
If you want to do this all within the same window, you could use a Grid as the root element and host a login element (possibly another grid for layout) and the chat window. These elements would stack on top of one another, depending upon the order in which you declare them. To hide the chat element initially, set its Visibility to Collapsed
You could then have the login element's Visibility set to Collapsed when the user submits their login details, and have the chat element's Visibility set to Visible.
I did something similar once and it worked well for me.
Hope that helps.
EDIT I knocked this together in Kaxaml for you to play with (and because I like playing with XAML):
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Border x:Name="_loginForm" BorderBrush="#888" BorderThickness="3" CornerRadius="5"
HorizontalAlignment="Center" VerticalAlignment="Center" Padding="10" Visibility="Visible">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" Height="30">Welcome to chat</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0">User Name</TextBlock>
<TextBox Grid.Row="1" Grid.Column="1" x:Name="_userName" />
<TextBlock Grid.Row="2" Grid.Column="0">Password</TextBlock>
<TextBox Grid.Row="2" Grid.Column="1" x:Name="_password"></TextBox>
<Button Grid.Row="3" Grid.Column="1">Log In</Button>
</Grid>
</Border>
<DockPanel x:Name="_chatForm" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" LastChildFill="True" Visibility="Collapsed">
<DockPanel DockPanel.Dock="Bottom" LastChildFill="True" Height="70">
<Button DockPanel.Dock="Right" Width="70">_Send</Button>
<TextBox x:Name="_input" HorizontalAlignment="Stretch">Hello world</TextBox>
</DockPanel>
<ListBox x:Name="_messageHistory" />
</DockPanel>
</Grid>
</Page>
Initially the element _loginForm is visible. You'd attach a handler for the Log In button's Click event that would hide it, and show the _chatForm instead.
This example shows usage of several layout controls -- the Grid, DockPanel and StackPanel.
Alternatively, you can use a StackPanel for your layout. As a simple example, you can have 2 elements in your panel; a custom login control as well as the chat 'display' control. After successfully logging in, remove the custom login control from your stack so only the chat is visible.
It's WPF! Animate them in and out of view...you can do that now. There's a collaborative project on Google Code called Witty (a desktop Twitter client written in WPF), and they do something really cool that you might want to borrow from. Come to think of it, there's another WPF Twitter client (blu) that does similar animations that you might want to look at.
In Witty, the Settings dialog is a normal window, but when you switch between the tabs, a storyboard slides the part of the window you requested into view. I haven't debugged the app at this level, but I'm assuming that they have a horizontal StackPanel populated with containers that are fixed to the height and width of the dialog, and they slide them in and out with a storyboard.
Take a look at both of these apps for ideas. You may want to do something similar, but being that this is a WPF app, the sky is really the limit.
Witty
blu
There are already some answers here on, how to swap two elements at the view level. This post offers a way to more fundamentally create a modular application design with interchangeable views.
You could take a look at the Composite Application Library. It is a small library (developed by Microsoft) that among other things aid in making your application more modular. With this you can define regions of your GUI, that can have interchangeable views.
In your containing xaml import the CAL namespace and use RegionManager to define a region:
<Window ...
xmlns:cal="http://www.codeplex.com/CompositeWPF"
...>
...
<ItemsControl cal:RegionManager.RegionName="MyRegion" />
...
Then you can swap views in this region, preferably in a module:
_regionManager.Regions["MyRegion"].Add(new LoginView());
...swap...
_regionManager.Regions["MyRegion"].Add(new ChatView());
This is of course just an outline of what you can do. In order to implement this solution, you will have to look further in to CAL. It has great documentation and lots of examples to learn from.
I think a more intuitive solution is to use a Frame control as the base control of your window - and to use the NavigateService to change the source of the Frame to different Page controls (which could be defined in separate assemblies, or in your same project as different XAML files).
Your Window:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Frame Source="LogonPage.xaml" NavigationUIVisibility="Hidden" />
</Window>
And your separate LogonPage:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Logon">
<!-- Your content of the page goes here... -->
</Page>

Categories