I have a property in a view model which I would like to be able to set via the XAML but I can't figure out how to do it.
I have a pretty basic user control (containing a list of items), two of which are to be placed on a page and I would like to be able to set one to be a 'Source' (defined by an enum) and one to be a 'Target'.
[The code below has been stripped down quite a bit so apologies if I've accidentally made some mistakes or missed something out.]
My enumeration is:
public enum ConversionSide
{
Source, // Convert something FROM whatever is here.
Target // Convert something TO whatever is here.
}
I have a page which looks like this:
<Page
x:Class="MyApp.Views.ConverterPage"
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:models="using:MyApp.Models"
xmlns:my="using:MyApp.Controls"
xmlns:prismMvvm="using:Prism.Windows.Mvvm"
prismMvvm:ViewModelLocator.AutoWireViewModel="True"
Style="{StaticResource PageStyle}"
mc:Ignorable="d">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<my:SelectorPage Name="SourceSelector" Grid.Column="0" />
<my:SelectorPage Name="TargetSelector" Grid.Column="1" />
</Grid>
</Page>
...where SelectorPage is a user control (I've called it a 'Page' to make the Prism AutoWire work but that's not the issue here) containing a list of items (all working fine) which looks like this...
<UserControl
x:Class="MyApp.Controls.SelectorPage"
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:models="using:MyApp.Models"
xmlns:my="using:MyApp.Controls"
xmlns:prismMvvm="using:Prism.Windows.Mvvm"
prismMvvm:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<ListView
Grid.Column="0"
ItemsSource="{x:Bind ViewModel.MyList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.MySelectedItem, Mode=TwoWay}">
<ListView.Header>
<TextBlock Margin="0,8,0,8" HorizontalAlignment="Center" FontStyle="Italic" Text="Header Text" />
</ListView.Header>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:MyListItem">
<my:MyListItemTemplate />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</UserControl>
..with code behind as...
public sealed partial class SelectorPage : UserControl
{
private SelectorViewModel ViewModel => DataContext as SelectorViewModel;
public SelectorPage()
{
this.InitializeComponent();
}
}
SelectorViewModel looks like this...
public class SelectorViewModel : ViewModelBase
{
private ConversionSide _side;
public ConversionSide Side
{
get { return _side; }
set { SetProperty(ref _side, value); }
}
// Many lines have been omitted for 'clarity'.
}
I would like to be able to set the Side property of SelectorViewModel in XAML like this...
<my:SelectorPage Name="SourceSelector" Grid.Column="0" Side="Source" />
<my:SelectorPage Name="TargetSelector" Grid.Column="1" Side="Target" />
(Once Side has been set, I do not expect it to ever change.)
How can I do this?
I've looked at using a dependency property but I can't get it to change the property in SelectorViewModel. When I add one in SelectorPage it's visible in the XAML and I can set it but it doesn't actually do anything so I'm probably not using it right. Putting a dependency property in the view model doesn't sound right to me but I could be wrong.
I've had a look around the web - Microsoft documentation, blogs, articles, stack overflow, etc. - but I can't find anything that explains things well enough for me to figure out what I'm supposed to do. The writings I've found seem to be exclusively about getting information from a bound property - which I'm okay with - but what I'm after is setting a property from the XAML.
Can anyone give my any clues please? I don't know if I'm just a tiny step away from getting what I want or if I'm miles away.
This would set the Side property of the SelectorPage control to Source:
A view sets the property of a view model by two-way bind to it. For example, the following TextBox sets the string property of a view model called Test when you change the text in the TextBox:
<TextBox Text="{Binding Test, Mode=TwoWay}" />
So setting the property of a view model from the view typically applies to controls that handles some kind of input. Any default value of a source property should be defined in the view model:
private ConversionSide _side = ConversionSide.Source;
You shouldn't define the default values in the view.
I am creating a universal app in Visual Studio 2015. My universal app has a reference to a universal library called UIComponents.
In UIComponents I created a user control:
namespace MyProj.UIComponents {
public sealed partial class MyControl : UserControl
{
public MyControl()
{
this.InitializeComponent();
}
}
}
With the following xaml:
<UserControl
x:Class="MyProj.UIComponents.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyProj.UIComponents"
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>
<Rectangle Fill="White" HorizontalAlignment="Left" Height="280" Stroke="Black" VerticalAlignment="Top" Width="380" Margin="10,10,0,0"/>
<TextBox x:Name="textBox" Margin="20,20,20,20" TextWrapping="Wrap" Text="TextBox"/>
</Grid>
</UserControl>
Inside my app project, which references UIComponents, I do this:
<Page
x:Class="MyProj.App.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyProj.App"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="using:MyProj.UIComponents"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ui:MyControl></ui:MyControl>
</Grid>
</Page>
But when I try to get the designer display the page I get:
The error list shows this:
The name "MyControl" does not exist in the namespace
"using:MyProj.UIComponents".
Funny thing is that the whole solution builds just fine, but the designer is not collaborating.
Attempt using clr-namespace
There are similar questions about this in WPF, so not strictly universal apps, and they are marked as solved on answers where the solution was to use:
xmlns:ui="clr-namespace:MyProj.UIComponents"
Bu that does not work:
Undefined CLR namespace. The 'clr-namespace' URI refers to a namespace
'MyProj.UIComponents' that could not be found.
The error list shows this:
The name "MyControl" does not exist in the namespace "using:MyProj.UIComponents".
In my experience, this could probably be caused by
The UIComponents Library didn't got built.
After building the Library project, VS will add the following codes into YourProject.proj file, which will be detected by VS designer:
<ItemGroup>//The following lines will be added.
<Page Include="MyControl.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
So, please try building your library project and rereference it in your main project.After reloading, designer should load the contents correctly.
Notes: The architecture(x64,x86) when building your library should be identical to current architecture. (e.g. when you build your library with x86. Designer can't load correctly, when your current architure is x64).
The namespace is wrong, which seems not the main cause here.
I have a XAML main window that contains a header, a central area and a footer (in a grid). The central area contains a ContentControl which is set throw a binding (using MVVMLight). The header/footer is always the same so no problems there.
The part that goes into the ContentControl is always quite similar, they are WPF usercontrols and have a left part that contains info and a right part with at least an OK and BACK button.
These are viewmodels and their views:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<TextBlock Text="this changes and contains other controls too" />
</Grid>
<Grid Grid.Column="1">
<!-- more buttons and statuses-->
<Button Content="Back" Margin="5" Height="30" />
<Button Content="Ok" Margin="5" Height="30" />
</Grid>
</Grid>
Is there a way i could create a base class/custom control for those views? So that I could write something like this in my xaml:
<basewindow>
<leftpart>
custom XAML for this view
</leftpart>
<rightpart>
custom XAML for this view
</rightpart>
</basewindow>
I could then remove duplicate code that is now in each of those views to the base class while still keeping the ability to write my xaml in the editor. Or is this not feasible?
To clarify are you trying to inherit the visual element that exist in XAML, like you can do in WinForms? If so you cannot do this in WPF. There is no Visual inheritence in WPF.
Now if you aren't trying to inherit visual element it is easy. First create your UserControlBase class and add you event handler. Keep in mind this base class can not have any XAML associated with it. Code only
public class MyUserControlBase : UserControl
{
public MyUserControlBase()
{
}
protected virtual void Button_Click(object sender, RoutedEventArgs e)
{
}
}
Now create another UserControl that does have a xaml counter part. Now you will need to change the root elemtn in the XAML to your base class like this:
<local:MyUserControlBase x:Class="WpfApplication7.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication7">
<Grid>
<Button Click="Button_Click">My Button</Button>
</Grid>
</local:MyUserControlBase>
And don't forget the code behind:
public partial class MyUserControl : MyUserControlBase
{
public MyUserControl()
{
InitializeComponent();
}
}
Notice the button in the derived user control is calling the Button_Click event handler we defined in the base class. That is all you need to do.
I'd like to switch only some part of my View (which is UserControl) xaml.
For example, I'd like to be able to change only 2nd Grid.
<Grid> //main grid
<Grid Name="1" Grid.Row="1"/>
<Grid Name="2" Grid.Row="2"/>
</Grid
I've tried sth like this:
<UserControl.Resources>
<ControlTemplate x:Key="UsualMode">
<Grid>
...
</Grid>
</ControlTemplate>
</UserControl.Resources>
<Grid> //main grid
<Grid Name="1" Grid.Row="1"/>
<ControlTemplate Name="2" Grid.Row="2" Template="{StaticResource UsualMode}"/>
</Grid>
Then, by using triggers and binding I would be able to switch templates.
Unfortunately, this doesn't work for me due to 'Bootstrapper.cs not found' exception.
How should I do that? I cannot use conductor -> have to load only one View.
http://caliburnmicro.codeplex.com/wikipage?title=All%20About%20Conventions
Read up on the basics of view resolution
Basically you would create the following in your view:
<UserControl.Resources>
<ControlTemplate x:Key="UsualMode">
<Grid>
...
</Grid>
</ControlTemplate>
</UserControl.Resources>
<Grid> //main grid
<Grid Name="1" Grid.Row="1"/>
<ContentControl x:Name="ChildViewModel" cal:View.Context="{Binding ContextBinding}" />
</Grid>
Your parent viewmodel needs to have a 'context' property and a property to house the child VM:
public class ParentViewModel
{
public SomeViewModel ChildViewModel { get; private set; }
public string ContextBinding { get; private set; } // make sure you implement INPC on these properties as is the usual
}
Your view will then be resolved based on the ContextBinding string (as per the CM conventions above).
So if you were to update the string:
ContextBinding = "DetailedView";
CM would then update the UI and try to look for a view called DetailedView in a subnamespace of the current VMs namespace
If you don't want to have a child VM, you can actually get CMs conventions to kick in earlier and apply a context over the current VM, but in this case you would need to create two views which were almost identical apart from the area which you would like to 'swap out'.
My preference would be to create a child VM to handle the sub-area that will swap views as I've shown above
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#.