WPF UserControl instead of Window in ViewModel - wpf

How can I change xaml of MenuManagement from Window to UserControl?
I want to use MenuManagement inside MainWindow xaml lik this:
this.mainViewModel = new MainWindow();
this.mainViewModel.Show();
this.mainViewModel.LayoutMain.Navigate(new MenuManagement());
but I receive error:
"Additional information: '***.Views.MenuManagement' root element is not valid for navigation."
My MenuViewModel:
class MenuViewModel : ViewModelBase<IMainView>
{
public MenuViewModel()
:base(new MenuManagement())
{ //...
}}
xaml of MenuManagment
<Window x:Class="***.Views.MenuManagement"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
Title="MenuManagement" Height="720" Width="1280">
<Grid>
...
</Grid>
MenuManagement
public partial class MenuManagement : Window, IMainView
{
public MenuManagement()
{
InitializeComponent();
} }
EDIT:
Interface
public interface IView
{
object DataContext { get; set; }
void Close();
}
public interface IMainView : IView
{
void Show();
}
}

Change this:
<Window x:Class="***.Views.MenuManagement"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
Title="MenuManagement" Height="720" Width="1280">
<Grid>
...
</Grid>
to:
<UserControl x:Class="***.Views.MenuManagement"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
Title="MenuManagement" Height="720" Width="1280">
<Grid>
...
</Grid>
</UserControl>
and this:
public partial class MenuManagement : Window, IMainView
{
public MenuManagement()
{
InitializeComponent();
}
}
to:
public partial class MenuManagement : UserControl, IMainView
{
public MenuManagement()
{
InitializeComponent();
}
}

Related

How to bind the window loaded event?

I want to bind the loaded event from my view so tha i can read some settings at the start. With some searching i made this but it does not work. what am i missing?
the view:
<UserControl x:Name="UserControlRegistratie" x:Class="Qbox_0001.Views.RegistratieView"
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" HorizontalContentAlignment="Left" VerticalContentAlignment="Top"
xmlns:intr="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
>
<intr:Interaction.Triggers>
<intr:EventTrigger EventName="Loaded">
<intr:InvokeCommandAction Command="{Binding Path=windowLoadedCommand}"/>
</intr:EventTrigger>
</intr:Interaction.Triggers>
<Grid x:Name="GridRegistratie">
.....
The viewmodel:
public class RegistratieViewModel
{
public RelayCommand windowLoadedCommand { get; private set; }
public RegistratieViewModel()
{
...
//commands
windowLoadedCommand = new RelayCommand(ExecuteWindowLoaded, CanExecute);
}
private bool CanExecute(object parameter)
{
return true;
}
private void ExecuteWindowLoaded(object parameter)
{
MessageBox.Show("window laden...........");
//Nothing happens
}
}
In my view i have this : (works for the other bindings)
public partial class RegistratieView : UserControl
{
public RegistratieView()
{
InitializeComponent();
DataContext = new RegistratieViewModel();
}
}

My static Model/Property is not binding to my UI

New to WPF.
I am trying to bind my Model to my UI. So, when the Property is changed during my User actions I want the field to update whereever it occurs on my UI.
This is my Model:
namespace WpfApplication1
{
public class model2
{
private static string myField2;
public static string MyField2
{
get { return myField2; }
set { myField2 = value; }
}
}
}
My Markup:
<Window x:Class="WpfApplication1.MainWindow"
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:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:model2 x:Key="mymodel"/>
</Window.Resources>
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Source={StaticResource ResourceKey=mymodel}, Path=MyField2}"></TextBlock>
<Button Content="static test!" Click="Button_Click_1" />
</StackPanel>
</Grid>
</Window>
My code behind:
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
model2.MyField2 = "static!";
}
}
}
The field on the UI does not change?
You need to notify changes to the UI so it can update with new values.
In your case you want to notify static properties of changes so you would need a static event. The problem is the INotifyPropertyChanged interface needs a member event so you won't be able to go that way.
You best shot is to implement the Singleton pattern:
namespace WpfApplication1
{
public class model2 : INotifyPropertyChanged
{
//private ctor so you need to use the Instance prop
private model2() {}
private string myField2;
public string MyField2
{
get { return myField2; }
set {
myField2 = value;
OnPropertyChanged("MyField2");
}
}
private static model2 _instance;
public static model2 Instance {
get {return _instance ?? (_instance = new model2();)}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) {
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And then make your property a member property and bind like this:
<Window x:Class="WpfApplication1.MainWindow"
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:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:model2 x:Key="mymodel"/>
</Window.Resources>
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Source={x:Static local:model2.Instance}, Path=MyField2}"/>
<Button Content="static test!" Click="Button_Click_1" />
</StackPanel>
</Grid>
</Window>
Code behind:
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
model2.Instance.MyField2 = "static!";
}
}
}
Use the Static extension to bind the TextBlocks Text Property:
<TextBlock Text="{Binding Source={Static MyModel.MyField2}, Mode=TwoWay">
But still the Property must raise the PropertyChanged event. My understanding why you use the static field is to be able to set the value from somewhere else. Have you thougt about using messages instead? Checkout the MVVM Light toolkit and the messenger. This would decouple the two components
I think that static properties are not what you want to use, from comments I can deduce that you are using only to make your program work. Below is the full working code.
App.xaml
Remove the code StartupUri="MainWindow.xaml instead we will instantiate MainWindow in code-behind to provide DataContext.
App.xaml.cs
Here we are assigning object of Model2 as Window.DataContext and then showing the window.
public partial class App : Application
{
public App()
{
Model2 model = new Model2();
MainWindow window = new MainWindow();
window.DataContext = model;
window.Show();
}
}
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
//We get hold of `DataContext` object
var model = this.DataContext as Model2;
model.MyField2 = "Hello World";
}
}
Model:
public class Model2 : INotifyPropertyChanged
{
private string _myField2;
public string MyField2
{
get { return _myField2; }
set
{
_myField2 = value;
OnPropertyChanged("MyField2");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
MainWindow.xaml
<Window x:Class="WpfApplication2.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>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding MyField2}"></TextBlock>
<Button Content="static test!" Click="ButtonBase_OnClick" />
</StackPanel>
</Grid>
</Window>
And I checked, it works !

How to use Message.Attach to call methods inside another object

I have a view model which has another class set as its property. The another class contains implementations of ICommand as its properties. I would like to execute one of the commands on a double click.
Unfortunatelly, Caliburn.Micro raises an exception instead ("No target found for method Commands.Command.Execute.").
I've tried to search the net and read the documentation, but without any success.
How to do it correctly?
Note: In real application, the message might be attached to a grid view which might have a different DataContext than the view model containing the commands class.
The XAML:
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<Grid>
<TextBox
cal:Message.Attach="[Event MouseDoubleClick]
= [Action Commands.Command.Execute(null)]" />
</Grid>
</Window>
The code-behind class:
namespace WpfApplication8
{
public partial class MainWindow
{
public Commands Commands { get; set; }
public MainWindow()
{
this.Commands =
new Commands { Command = new Command { MainWindow = this } };
this.InitializeComponent();
this.DataContext = this;
}
}
public class Commands
{
public Command Command { get; set; }
}
public class Command
{
public MainWindow MainWindow { get; set; }
public void Execute(object parameter)
{
this.MainWindow.Title = "Executed";
}
}
}
As #alik commented, complete solution is:
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<Grid>
<TextBox
cal:Message.Attach="[Event MouseDoubleClick] = [Action Execute(null)]"
cal:Action.TargetWithoutContext="{Binding Commands.Command}"/>
</Grid>
</Window>

Basic Silverlight Binding

I can't figure out why the binding changes in my large project wont work. I have simplified it down to a sample project that still doesn't work. I would like to continue to set the datacontext the way I currently am if possible because that is how the other project does it. With the following code the text in SomeText is not showing up in the textbox. How do I fix this?
Code Behind:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
Data Class:
public class ViewModel
{
public string SomeText = "This is some text.";
}
Main User Control:
<UserControl xmlns:ig="http://schemas.infragistics.com/xaml" x:Class="XamGridVisibilityBindingTest.MainPage"
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:XamGridVisibilityBindingTest="clr-namespace:XamGridVisibilityBindingTest" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<TextBox Text="{Binding SomeText}" BorderBrush="#FFE80F0F" Width="100" Height="50"> </TextBox>
</Grid>
</UserControl>
Edit: I am only trying to do one-way binding.
You need to use a property, and make your VM inherit from INotifyPropertyChanged and raise the PropertyChanged event whenever SomeText changes:
public class ViewModel : INotifyPropertyChanged
{
private string someText;
public event PropertyChangedEventHandler PropertyChanged;
public string SomeText
{
get { return someText; }
set
{
someText = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("SomeText"));
}
}
}
public ViewModel()
{
SomeText = "This is some text.";
}
}
I figured it out, you can only bind to Properties!
public class ViewModel
{
public string SomeText { get; set; }
public ViewModel()
{
SomeText = "This is some text.";
}
}

How to access a named element of a derived user control in silverlight?

I have a custom base user control in silverlight.
<UserControl x:Class="Problemo.MyBaseControl"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Border Name="HeaderControl" Background="Red" />
</Grid>
</UserControl>
With the following code behind
public partial class MyBaseControl : UserControl
{
public UIElement Header { get; set; }
public MyBaseControl()
{
InitializeComponent();
Loaded += MyBaseControl_Loaded;
}
void MyBaseControl_Loaded(object sender, RoutedEventArgs e)
{
HeaderControl.Child = Header;
}
}
I have a derived control.
<me:MyBaseControl x:Class="Problemo.MyControl"
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"
mc:Ignorable="d"
xmlns:me="clr-namespace:Problemo"
d:DesignHeight="300" d:DesignWidth="400">
<me:MyBaseControl.Header>
<TextBlock Name="header" Text="{Binding Text}" />
</me:MyBaseControl.Header>
</me:MyBaseControl>
With the following code behind.
public partial class MyControl : MyBaseControl
{
public string Text
{
get; set;
}
public MyControl(string text)
{
InitializeComponent();
Text = text;
}
}
I'm trying to set the text value of the header textblock in the derived control.
It would be nice to be able to set both ways, i.e. with databinding or in the derived control code behind, but neither work. With the data binding, it doesn't work. If I try in the code behind I get a null reference to 'header'. This is silverlight 4 (not sure if that makes a difference)
Any suggestions on how to do with with both databinding and in code ?
Cheers
First of all I'll show you how to adjust your Derived control to handle this. You need to do two things, first you need to implement INotifyPropertyChanged and secondly you to add the binding to the user control.
MyControl Xaml:-
<me:MyBaseControl.Header>
<TextBlock Name="headerItem" />
</me:MyBaseControl.Header>
MyControl code:-
public partial class MyControl : MyBaseControl, INotifyPropertyChanged
{
public MyControl ()
{
InitializeComponent();
headerItem.SetBinding(TextBlock.TextProperty, new Binding("Text") { Source = this });
}
string _text;
public string Text
{
get { return _text; }
set { _text = value; NotifyPropertyChanged("Text"); }
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
void NotifyPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
#endregion
}
This should get you working. However, as soon as you feel you need to inherit a UserControl based class you should take a step back and ask whether the base and derived items ought to be templated controls instead. If I get time I'll try to add a version of your code in terms of templated controls.

Resources