I am working on an application for my office using WPF with Prism, and I've hit a roadblock. I found a webinar hosted by Brian Lagunas (one of the developers of Prism) that was doing several of the things that I need to do in this app, so I basically followed along and changed namespaces, etc to fit my app.
The Solution will compile but it throws an exception when I try to navigate using the ContentControl with Prism:RegionManager.RegionName.
The Solution has 2 projects. The first project calls the MainWindow of the 2nd project. My code is below.
Project 1 - MainWindow
namespace AdjusterToolV2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private void btnLetters_Click(object sender, RoutedEventArgs e)
{
URLetters.MainWindow frm1 = new URLetters.MainWindow();
frm1.Show();
}
}
}
Prism Bootstrapper
using Prism.Unity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Practices.Unity;
using URLetters.Views;
namespace URLetters
{
public class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow.Show();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterType(typeof(object), typeof(PHLtrWithEvidenceView), "PHLtrWithEvidenceView");
}
}
}
XAML for project 2 main page (code behind is empty)
<Controls:MetroWindow x:Class="URLetters.MainWindow"
xmlns= "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:d= "http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
xmlns:local="clr-namespace:URLetters"
mc:Ignorable="d"
Title="Unresolved Liability Letters"
Height="500"
Width="700"
Icon="../Resources/GEICO.ico"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<DockPanel Grid.Column="0" Background="#154995" HorizontalAlignment="Left" LastChildFill="False" Width="120">
<StackPanel Grid.Column="0">
<Button x:Name="btn48hrWithEvidence"
Command="{Binding NavigateCommand}"
CommandParameter="PHLtrWithEvidenceView"
x:FieldModifier="public"
Height="40"
Width="100"
Margin="10,10,0,0"
ToolTip="Letter to the PH with a 48 hour contact time limit. Used when evidence has been provided by the claimant" >
<TextBlock FontSize="11" Text="48 Hour - PH With Evidence" TextWrapping="Wrap" TextAlignment="Center" />
</Button>
<Button x:Name="btn48hrNoEvidence"
Height="40"
Width="100"
Margin="10,10,0,0"
ToolTip="Letter to the PH with a 48 hour contact time limit. Used when there is no evidence provided by the claimant" >
<TextBlock FontSize="11" Text="48 Hour - PH With No Evidence" TextWrapping="Wrap" TextAlignment="Center" />
</Button>
<Button x:Name="btnNoCtcPH"
Height="40"
Width="100"
Margin="10,10,0,0"
ToolTip="Letter to the PH advising them that we have reached an AT FAULT liability decision based on the evidence provided." >
<TextBlock FontSize="11" Text="No Contact - PH Liability Decision" TextWrapping="Wrap" TextAlignment="Center" />
</Button>
<Button x:Name="btnNoCtcPHLiabDenial"
Height="40"
Width="100"
Margin="10,10,0,0"
ToolTip="Letter to the PH advising them that we have denied liability because we have no evidence to support the PH involvement" >
<TextBlock FontSize="11" Text="No Contact - PH Liability Denial" TextWrapping="Wrap" TextAlignment="Center" />
</Button>
<Button x:Name="btnNoCtcCLMTLiabDenial"
Height="40"
Width="100"
Margin="10,10,0,0"
ToolTip="Letter to the CLAIMANT advising that we have denied liability because we have no evidence to support the PH involvement" >
<TextBlock FontSize="11" Text="No Contact - CLMT Liability Denial" TextWrapping="Wrap" TextAlignment="Center" />
</Button>
</StackPanel>
</DockPanel>
<DockPanel x:Name="ContentRegionName" Grid.Column="1">
<ContentControl prism:RegionManager.RegionName="ContentRegion"/>
</DockPanel>
</Grid>
</Controls:MetroWindow>
ViewModel for project 2 mainwindow
using Prism.Mvvm;
using Prism.Regions;
using Prism.Commands;
namespace URLetters.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private readonly IRegionManager _regionManager;
public DelegateCommand<string> NavigateCommand { get; set; }
public MainWindowViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
NavigateCommand = new DelegateCommand<string>(Navigate);
}
private void Navigate(string uri)
{
_regionManager.RequestNavigate("ContentRegion", uri);
}
}
}
It throws the exception in the XAML file on this line:
<ContentControl prism:RegionManager.RegionName="ContentRegion"/>
exception reads: "Exception thrown: 'System.Windows.Markup.XamlParseException' in PresentationFramework.dll
Additional information: 'Set property 'Prism.Regions.RegionManager.RegionName' threw an exception.' Line number '69' and line position '14'."
This happens when I click the btnLetters button. The URLetters MainWindow does not open and then the exception is thrown. I've gone back over the code, and checked it against the examples in the webinar and I can't figure out why the exception is being thrown.. Help would be greatly appreciated.
It doesn't look like you have your application setup properly. Your Bootstrapper should be the class responsible for showing your MainWindow. You should not have any StartupUri in your App.xaml. There is obviously something wrong with how you have your project setup, but there is not enough information in your post for me to give a definite answer. Plus, having 2 MainWindows is confusing me :)
Download and install the Prism Template Pack: https://visualstudiogallery.msdn.microsoft.com/e7b6bde2-ba59-43dd-9d14-58409940ffa0
Then create a new Prism Unity App for WPF. It will stub out your application for you properly. Then just start adding your Views and ViewModels
Related
I started to use MVVMLight framework recently.
When I use ContentPresenter to swtich between ViewModel, it seems like it initialize the datacontext when it first displays.
However, I want it to initialize it's datacontext so it can keep track of any change from the initial loading of the application, or at least share the data with other viewmodel(I assume maybe I can use dataservice to keep track of all the data, but I could not find a right example to use it with contentpresenter & MVVMLight).
Below is the sample code I made. When I click Review button, "usercontrolview" will display "Picture Saved", however "contentpresenterview" will display "No Picture".
Sample Image
MainView.xaml
<Grid>
<Button x:Name="CaptureButton" Content="Capture" HorizontalAlignment="Left" Margin="34,10,0,0" VerticalAlignment="Top" Width="75"
Command="{Binding CaptureCommand}"/>
<Button x:Name="ReviewButton" Content="Review" HorizontalAlignment="Left" Margin="146,10,0,0" VerticalAlignment="Top" Width="75"
Command="{Binding ShowReviewCommand}"/>
<TextBlock FontSize="36"
FontWeight="Bold"
Foreground="Purple"
Text="{Binding CaptureStatus}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
TextWrapping="Wrap" />
<Grid x:Name="usercontrolview" Visibility="{Binding ReviewModeOn, Converter={StaticResource BooleanToVisibilityConverter}}" Margin="0,50,150,0">
<view:ReviewView/>
</Grid>
<ContentPresenter x:Name="contentpresenterview" Content="{Binding CurrentContent}" Margin="150,50,0,0"/>
</Grid>
MainViewModel.cs (Partial)
public MainViewModel()
{
CaptureStatus = "No Picture";
CaptureCommand = new RelayCommand(Capture);
ShowReviewCommand = new RelayCommand(ShowReview);
ReviewModeOn = false;
}
public RelayCommand CaptureCommand { get; private set; }
private void Capture()
{
CaptureStatus = "Pictures Saved";
Messenger.Default.Send<NotificationMessage>(new NotificationMessage("Pictures Saved"), "Captured");
}
public RelayCommand ShowReviewCommand { get; private set; }
private void ShowReview()
{
ReviewModeOn = !ReviewModeOn;
CurrentContent = ContentViewModel;
}
And my template for ReviewViewModel & ReviewContentPresenterViewModel
public ***ViewModel()
{
Messenger.Default.Register<NotificationMessage>(this, "Captured", Captured);
CaptureStatus = "No Picture";
}
private void Captured(NotificationMessage notificationMessage)
{
CaptureStatus = notificationMessage.Notification;
}
private string _captureStatus;
public string CaptureStatus
{
get { return _captureStatus; }
set { Set(ref _captureStatus, value); }
}
======================= Update =======================
My template for ReviewView & ReviewContentPresenterView.
It takes DataContext by locator.
<UserControl x:Class="***View"
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:ignore="http://www.galasoft.ch/ignore"
mc:Ignorable="d ignore"
DataContext="{Binding ***ViewModel, Source={StaticResource Locator}}">
<Grid Background="Gray">
<TextBlock FontSize="36"
FontWeight="Bold"
Foreground="Purple"
Text="{Binding CaptureStatus}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
TextWrapping="Wrap" />
</Grid>
</UserControl>
It seems your DataContext in the root Grid and all it's children is the MainViewModel and you want other DataContext for ContentPresenter. Create the other ViewModel as a resource e.g.
<Grid>
<Grid.Resources>
<local:TheViewModelIWant x:Key=ContentViewModel/>
</Grid.Resources>
...
...
<ContentPresenter DataContext={StaticResource ContentViewModel} ...
(By the way, if you are already creating an instance of TheViewModelIWant somewhere e.g. in other ViewModels or view code behind then you can stop using that instance and access this instance in C# code as Resources["ContentViewModel"])
This is a newbie question about using Avalon Dock and Caliburn.Micro together. First I got a simple example of Caliburn.Micro working, taken from the Mindscape blog's excellent tutorial on Caliburn Micro. This example consists of a main window called MainShellView:
<UserControl x:Class="TestApp.MainShellView"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Width="300" Height="300" Background="LightBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ContentControl Name="ColorModel" Margin="10"/>
<Rectangle Width="100" Height="100" Fill="{Binding Color}" Grid.Column="1"/>
</Grid>
</UserControl>
where ColorView is made of three radio buttons:
<UserControl x:Class="TestApp.ColorView">
<Grid>
<RadioButton Name="Red" Content="Red" Foreground="White"
VerticalAlignment="Center" HorizontalAlignment="Center" />
<RadioButton Name="Green" Content="Green" Foreground="White"
VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="1" />
<RadioButton Name="Blue" Content="Blue" Foreground="White"
VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="2" />
</Grid>
</UserControl>
The class behind MainShellView has a Color property:
public class MainShellViewModel : PropertyChangedBase, IHandle<ColorEvent>
{
public SolidColorBrush Color
{
get { ... }
set { ... }
}
}
and Caliburn.Micro sets the color of the rectangle on the right in MainShellView to the color selected by the radio buttons:
[Export(typeof(ColorViewModel))]
public class ColorViewModel
{
public void Red()
{
_events.PublishOnUIThread(new ColorEvent(new SolidColorBrush(Colors.Red)));
}
public void Green() { /* something similar */ }
public void Blue() { /* something similar */ }
}
I then tried replacing the Grid in the MainShellView by an AvalonDock layout, with the ColorView in one document and the colored rectangle in another document:
<UserControl x:Class="TestApp.MainShellView"
xmlns:local="clr-namespace:TestApp"
d:DesignHeight="300" d:DesignWidth="300">
<avalon:DockingManager>
<avalon:LayoutRoot>
<avalon:LayoutPanel>
<avalon:LayoutDocumentPane>
<avalon:LayoutDocument Title="Document 1">
<ContentControl Name="ColorModel"/>
</avalon:LayoutDocument>
</avalon:LayoutDocumentPane>
<avalon:LayoutDocumentPane>
<avalon:LayoutDocument Title="Document 2">
<Rectangle Width="100" Height="100" Fill="{Binding Color}" Grid.Column="1"/>
</avalon:LayoutDocument>
</avalon:LayoutDocumentPane>
</avalon:LayoutPanel>
</avalon:LayoutRoot>
</avalon:DockingManager>
</UserControl>
However the ColorView doesn't appear on the left hand side. The Caliburn binding also fails - stepping through the Caliburn source code, this is because the VisualTreeHelper can't see the ColorView.
I've abbreviated the source code above, and put the full source in https://github.com/BobMortimer/SO_Question1 .
I'm certainly doing something stupid. So why is this not working, and how can I fix it?
I think you are missing 2 overrides in bootstrapper for
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
return container.GetExportedValues<object>(
AttributedModelServices.GetContractName(serviceType));
}
and
protected override void BuildUp(object instance)
{
container.SatisfyImportsOnce(instance);
}
surprisingly enough it ran but didn't do what it was suppose to based on the source you provided in github. As you said on the debugger it dies, was it IoC not Initialized?
I'm new to Prism. I'm trying to setup a test project on Prism. I download Prism 4.1 as I found out Prism 5 doesn't work with Silverlight 5 Yet. so My configuration is Like this.
I've visual studio 2013 , Silverlight 5 and .Net 4.5.1. A basic exercise 1 Homepage divided in to 2 parts with 2 Prism module I followed for Hello world example. Done and working 1 Region Hello, 2end Regigon world
Now in Hello Module I create 1 User form. Created 1 Use.cs with INotifyPropertyChanged etc. Followed MVVM. For created Data Appeared in form. Bow I bind 1 Submit button and display change date on the same region.
I used DelegateCommand. Now working .
No Bug shown But No firing of event.
Project Structure is Like this
.Net Silverlight Navigation Application
aprism
Shell.xaml
Bootstrapper.cs
aprism.web
aprism.Hello
HelloView.xaml
HelloView.xamal.cs : UserControl , IHelloView
IHelloView : IView
IHelloViewModel : IViewModel
HelloViewModel : ViewModelBase, IHelloViewModel
aprism.World
aprism.Business
User.cs : INotifyPropertyChanged , IDataErrorInfo
aprism.Infrastructure
IView
IViewModel
ViewMode
public interface IView
{
IViewModel ViewModel { get; set; }
}
public interface IViewModel
{
IView View { get; set; }
}
public class ViewModelBase :IViewModel ,INotifyPropertyChanged
{
public ViewModelBase(IView view) {
View = view;
View.ViewModel = this;
}
public IView View
{
get;
set;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName) {
if (PropertyChanged != null)
{
PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
}
}
}
public class HelloViewModel : ViewModelBase, IHelloViewModel
{
public DelegateCommand SubmitRegistrationForm { get; set; }
public HelloViewModel(View.IHelloView view):base(view)
{
this.View = view;
this.View.ViewModel = this;
this.HelloText = "Prism Hello..";
CreateUse();
//User.PropertyChanged +=User_PropertyChanged;
this.SubmitRegistrationForm = new DelegateCommand(Save, CanSave);
}
/* private void User_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
SubmitRegistrationForm.RaiseCanExecuteChanged();
}*/
private bool CanSave()
{
return true;
}
private void Save()
{
User.DateUpdated = DateTime.Now;
}
#region IHelloViewModel Members
public string HelloText { get; set; }
private User _user;
public User User {
get { return _user; }
set
{
_user = value;
OnPropertyChanged("User");
}
}
private void CreateUse() {
User = new User()
{
Username="Anand",
Email = "akirti.iitk#gmail.com",
Password = "delasoft",
ConfirmPassword = "delasoft"
};
}
/* public Infrastructure.IView View
{
get;
set;
}
*/
#endregion
}
<UserControl
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:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="Hpmsprism.Hello.View.HelloView"
mc:Ignorable="d"
xmlns:local="clr-namespace:Hpmsprism.Business;assembly=Hpmsprism.Business"
xmlns:Commands="clr-namespace:Microsoft.Practices.Prism.Commands;assembly=Microsoft.Practices.Prism"
d:DesignHeight="500" d:DesignWidth="500">
<UserControl.Resources>
<local:User x:Key="cUser"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock Text="{Binding HelloText}" FontSize="26" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="10"/>
<TextBlock HorizontalAlignment="Left" Margin="98,35,0,0"
TextWrapping="Wrap" Text="User Registration"
VerticalAlignment="Top" FontSize="20"/>
<sdk:Label HorizontalAlignment="Left"
Height="28" Margin="110,96,0,0"
VerticalAlignment="Top" Width="90" Content=" User Name : "/>
<sdk:Label HorizontalAlignment="Left"
Height="28" Margin="110,129,0,0"
VerticalAlignment="Top" Width="90" Content=" Email : "/>
<sdk:Label HorizontalAlignment="Left"
Height="28" Margin="110,157,0,0"
VerticalAlignment="Top" Width="90" Content=" Password : "/>
<sdk:Label HorizontalAlignment="Left"
Height="28" Margin="110,204,0,0"
VerticalAlignment="Top" Width="124" Content=" Confirm Password : "/>
<Button Content="Register" HorizontalAlignment="Left" Margin="342,301,0,0"
VerticalAlignment="Top" Width="75" x:Name="SubmitRegisterForm" Commands:Click.Command="{Binding Path=SubmitRegistrationFormCommand}"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="247,92,0,0"
TextWrapping="Wrap" Text="{Binding User.Username,Mode=TwoWay,ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="170" x:Name="UserName"
/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="247,125,0,0"
TextWrapping="Wrap" Text="{Binding User.Email,Mode=TwoWay,ValidatesOnDataErrors=True}" VerticalAlignment="Top" Width="170" x:Name="Email"/>
<PasswordBox HorizontalAlignment="Left" Margin="247,157,0,0"
VerticalAlignment="Top" Width="170" x:Name="Password"
Password="{Binding User.Password,Mode=TwoWay,ValidatesOnDataErrors=True}"/>
<PasswordBox HorizontalAlignment="Left" Margin="247,200,0,0"
VerticalAlignment="Top" Width="170" x:Name="ConfirmPassword"
Password="{Binding User.ConfirmPassword,Mode=TwoWay,ValidatesOnDataErrors=True}"/>
<sdk:Label HorizontalAlignment="Left" Height="28" Margin="110,257,0,0"
VerticalAlignment="Top" Width="120" Content=" Date Updated :"/>
<TextBlock HorizontalAlignment="Left" Margin="230,257,0,0" TextWrapping="Wrap"
Text="{Binding User.DateUpdated}" VerticalAlignment="Top" x:Name="DateUpdated"/>
</Grid>
</UserControl>
My Button Doesn't fire Submit Command.
PLease Help me.
Thank you
Finally I got It working. After Polishing my MVVM Concept & Unity Again.
Problem is Any Property used in HelloViewModel should have the signature in IHelloViewModel Interface too. And for this Property I Need to Implement INotifyPropertyChanged too.
So I did Like this :
private DelegateCommand _command;
public DelegateCommand SubmitRegistrationFormCommand
{
get { return _command; }
set { _command = value; OnPropertyChanged("SubmitRegistrationFormCommand"); }
}
// This in Implementation
and In Interface I had a Property Signature to Like this
DelegateCommand SubmitRegistrationFormCommand{set;get;}
This may be When Ioc Loads & Map this interface is the role play Thing as DataContext is of Type this ViewModel after Setting the Property
http://social.msdn.microsoft.com/Forums/en-US/531eb18f-3060-4adf-a44e-8dffe0fcbd07/prism-41-silverlight-5-with-net-451-delegatecommand-not-working?forum=wpf
Initially Didn't work for me until I didn't mapped my Interface.
I've written a code for a simple calculator in wpf .
My MainWindow.Xaml code is..
<Window x:Class="CalculatorNew.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid ContextMenuClosing="Multi">
<TextBox x:Name="TextBox1" HorizontalAlignment="Left" Height="23" Margin="216,23,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" RenderTransformOrigin="0.679,0.552"/>
<TextBox x:Name="TextBox2" HorizontalAlignment="Left" Height="23" Margin="216,76,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" RenderTransformOrigin="0.679,0.552"/>
<TextBox x:Name="TextBox3" HorizontalAlignment="Left" Height="23" Margin="216,121,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" RenderTransformOrigin="0.679,0.552"/>
<TextBlock HorizontalAlignment="Left" Margin="68,30,0,0" TextWrapping="Wrap" Text="First Number" VerticalAlignment="Top" RenderTransformOrigin="1.137,1.259" Height="16" Width="80"/>
<TextBlock HorizontalAlignment="Left" Margin="68,128,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="1.137,1.259" Height="16" Width="80" Text="Result"/>
<TextBlock HorizontalAlignment="Left" Margin="68,83,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="1.137,1.259" Height="16" Width="99" Text="Second Number"/>
<Button Content="+" HorizontalAlignment="Left" Margin="73,172,0,0" VerticalAlignment="Top" Width="75" Click="Add"/>
<Button Content="-" HorizontalAlignment="Left" Margin="179,172,0,0" VerticalAlignment="Top" Width="75" Click="Sub"/>
<Button Content="*" HorizontalAlignment="Left" Margin="286,172,0,0" VerticalAlignment="Top" Width="75" Click="Multi"/>
<Button Content="/" HorizontalAlignment="Left" Margin="392,172,0,0" VerticalAlignment="Top" Width="75" Click="Div"/>
</Grid>
My MainWindowdow.Xaml.cs code is..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace CalculatorNew
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Add(object sender, RoutedEventArgs e)
{
TextBox3.Text = (System.Convert.ToDecimal(TextBox1.Text) + System.Convert.ToDecimal(TextBox2.Text)).ToString();
}
private void Sub(object sender, RoutedEventArgs e)
{
TextBox3.Text = (System.Convert.ToDecimal(TextBox1.Text) - System.Convert.ToDecimal(TextBox2.Text)).ToString();
}
private void Div(object sender, RoutedEventArgs e)
{
TextBox3.Text = (System.Convert.ToDecimal(TextBox1.Text) / System.Convert.ToDecimal(TextBox2.Text)).ToString();
}
private void Multi(object sender, RoutedEventArgs e)
{
TextBox3.Text = (System.Convert.ToDecimal(TextBox1.Text) * System.Convert.ToDecimal(TextBox2.Text)).ToString();
}
}
}
I am new to WPF and MVVM . So I am finding it a bit difficult to write it in the MVVM format .
Can someone tell me how to rewrite it in MVVM format so that I can use it as a reference for the future?
I think your question has a high chance of being closed because it doesn't demonstrate a minimum willingness to make an effort on your part. Please read a tutorial, there are plenty on the web, and try to understand the concepts first. You need at the very least to understand what a ViewModel is, and how the View relates to it (bindings).
You will probably not get working code that does exactly what you want on this site, I for one am much more interested in explaining how things work.
Anyway, in order to get what you want you need a class that acts as the ViewModel with properties that represent the concepts that you work with. You could have decimal properties that represent the operands and something that represents the operator, and commands that represent each button in the UI. Then you need bindings that link UI elements (textboxes, buttons) to the properties in the ViewModel, and you need to set an instance of the ViewModel as the DataContext of the container for the UI elements you're interested in (be it a Window, Grid or whatever). I think that pretty much sums it up...
You can use this example as a reference. https://code.google.com/p/wpf-mvvm-calculator/downloads/list
I'm trying to build a very simple and basic application that adds tab items to tab control using the MVVM pattern.
So i created:
a simple view with one button - "CustomerView.xaml"
an empty ViewModel class - it is empty cause the view doesn't save or extract any information from the Viewmodal (have only one button) - "CustomerViewModel.cs"
The MainWindow class code holds an observable collection of the CustomerViewModel
and have one "Add customer" button - to add a customer tab item to the tabcontrol and the tabcontrol itself.
i don't use commands cause it is not relevant at this time , i just was the new tabitem to appear when i add a new CustomerViewModel to the collection.
the result is that , although i can see that CustomerViewModels are added to the Observable collection, i still don't see tabitems added to the tabcontrol - The collection is not updating the the tabcontrol.
This is the MainWindow XAML:
<Window x:Class="MyViewModalTabControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:MyViewModalTabControl.ViewModal"
xmlns:vw="clr-namespace:MyViewModalTabControl.Views"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type vm:CustomerViewModel}">
<vw:CustTabView />
</DataTemplate>
<DataTemplate x:Key="ClosableTabItemTemplate">
<DockPanel Width="120">
<Button
Content="X"
Cursor="Hand"
DockPanel.Dock="Right"
Focusable="False"
FontFamily="Courier"
FontSize="9"
FontWeight="Bold"
Margin="0,1,0,0"
Padding="0"
VerticalContentAlignment="Bottom"
Width="16" Height="16"
/>
<ContentPresenter
Content="Sample"
VerticalAlignment="Center"
/>
</DockPanel>
</DataTemplate>
</Window.Resources>
<Grid Margin="4" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Name="CustTabButton" Content="New Customer" Height="30" Margin="12,136,9,136" Click="CustTabButton_Click"></Button>
<TabControl Grid.Column="1" Grid.Row="0" Background="Red"
ItemsSource="{Binding CustomerTabs}"
ItemTemplate="{StaticResource ClosableTabItemTemplate}"
>
</TabControl>
</Grid>
This is the code behind of the MainWindow:
public partial class MainWindow : Window
{
private ObservableCollection<CustomerViewModel> _customertabs;
public ObservableCollection<CustomerViewModel> CustomerTabs
{
get
{
if (_customertabs == null)
{
_customertabs = new ObservableCollection<CustomerViewModel>();
// _workspaces.CollectionChanged += this.OnWorkspacesChanged;
}
return _customertabs;
}
}
public MainWindow()
{
InitializeComponent();
}
private void CustTabButton_Click(object sender, RoutedEventArgs e)
{
CustomerViewModel CustomerWorkSpace = new CustomerViewModel();
this.CustomerTabs.Add(CustomerWorkSpace);
}
}
This is the Viewmodel class:
public class CustomerViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
}
This is the View :
UserControl x:Class="MyViewModalTabControl.Views.CustTabView"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Button Name="CustTabButton" Content="New Customer" Height="30" Margin="12,136,9,136"></Button>
</Grid>
What am i missing ?
where do you set the datacontext for your mainwindow? Your bindings will just work with the right Datacontext.
and wouldn't it be better to create a mainviewmodel too, which handles the stuff you put in the mainwindow.cs at the moment?
EDIT: pls look at this msdn post from josh smith. there you can find a closable tab too.
Try any of the following
the ClosableTabItemTemplate should "return" TabItem that will be displayed in the Tab control not the DockPanel
create template for the TabItem control
do it in code
This is the fix:
public MainWindow()
{
InitializeComponent();
this.DataContext=this;
}