Window Binding to UserControl ViewModel - c#

I need help with binding a window to a user control view model. Here's my user control, nice and simple.
<UserControl x:Class="WindowBindTest.UserControlTest"
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"
xmlns:ViewModel="clr-namespace:WindowBindTest.UserControlViewModel"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<ViewModel:UserControlViewModel></ViewModel:UserControlViewModel>
</UserControl.DataContext>
<Grid>
</Grid>
</UserControl>
Here's my view model
namespace WindowBindTest
{
public class UserControlViewModel
{
public Window hostWindow { get; set; }|
public UserControlViewModel()
{
// I want to set the host window
// If something isn't defined then close the host window.
}
}
}
I could use a button to close the window but what if I didn't want to use a button. Is there a way to do that?
Could I pass in the parent window into the constructor?

You can do this in MVVM but you will need to use a service. In fact, this is where MVVM is weak (without using a framework such as Prism et al.). The following is a link to disore's DialogService class on CodeProject. it is awesome, but it will take time to get to grips with how it works.
The above library will enable you to close a View from a ViewModel.
I hope this helps.

Related

WPF: Problem with display xaml view inherits from UserControl

Hello i have this Viw in XAML
<local:JedenViewBase x:Class="Firma.View.FakturaView"
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:Firma.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary Source="MainWindowResource.xaml" />
</UserControl.Resources>
<Grid>
.....
</Grid>
</local:JedenViewBase>
And that is class this view
namespace Firma.View
{
public partial class FakturaView : JedenViewBase
{
public FakturaView()
{
InitializeComponent();
}
}
}
And that is JedenViewBase class
namespace Firma.View
{
public class JedenViewBase : UserControl
{
static JedenViewBase()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(JedenViewBase), new FrameworkPropertyMetadata(typeof(JedenViewBase)));
}
}
}
I have problem because view in XAML dont display, i dont know why? JedenViewBase class inherits from UserControl. When i UserControl in view everything works. What i should do?
<UserControl x:Class="Firma.View.FakturaView"
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:Firma.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary Source="MainWindowResource.xaml" />
</UserControl.Resources>
<Grid>
...
</Grid>
</UserControl>
View FakutraView when i use UserControl
I try rebuild app etc. and i still have problem
You've created a custom control.
That's unlikely to be a good idea and this should probably just be a user control.
The reason you get no view is this.
static JedenViewBase()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(JedenViewBase), new FrameworkPropertyMetadata(typeof(JedenViewBase)));
}
I recommend you remove that. Change
<local:JedenViewBase
To user control.
Make this just a user control.
Alternatively. Read up on custom controls. Put your ui definition in generic xaml.
I also wonder why this has it's own resources. They will be in memory for each instance. If whatever is in that resource dictionary is unique to this control maybe that's not a bad idea. in which case the naming seems strange.

In WPF Prism MVVM, How to resize Parent view from Child View

In MVVM application using Prism, a child view and viewmodel is loaded in parent view UserControl "ContentRegion"
and parent view has fixed size
Height="868"
Width="1024"
MinHeight="868"
MinWidth="1024"
How to resize parent view size from child viewmodel
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:prism="http://prismlibrary.com/"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
prism:ViewModelLocator.AutoWireViewModel="True"
Height="868"
Width="1024"
MinHeight="868"
MinWidth="1024">
<Grid>
<UserControl prism:RegionManager.RegionName="ContentRegion" />
</Grid>
</Window>```
I would not recommend trying to resize the parent window from a view as it does not know where it is located.
Try to play with SizeToContent.
If your really need to resize it manually, you can use Prism's IEventAggregator using PubSubEvent<T> to Publish() und Subscribe() events.
From within the View's context you'll want to Publish() the event.
And on the Window you Subscribe() to that event and handle the sizing parameters.
Pseudo code:
public class ResizeParentWindowEvent : PubSubEvent<YourSizeInfo> { }
eventAggregator.GetEvent<ResizeParentWindowEvent>().Publish(your_size_info_object);

WPF usercontrol mvvm

I have a problem implementing MVVM with a usercontrols.
I have an MVVM based application.
In one of the view (which is a usercontrol) I have a menu on the left and content on the right. The content change depending on the menu.
I tried to implement the MVVM with a usercontrol, but i dont know how.
Here is what i tried but it didn't work :
<UserControl x:Class="PoS.Views.OptionsView"
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:local="clr-namespace:PoS.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<DataTemplate x:Name="SettingsTemplate" DataType="{x:Type viewmodels:SettingsViewModel}">
<views:SettingsView DataContext="{Binding}" />
</DataTemplate>
</UserControl.Resources>
<Grid>
</Grid>
</UserControl>
I'll be honest, I think you need to rewind a bit and read a good book on MVVM before continuing. Gary McLean Hall's Pro WPF and Silverlight MVVM is a good place to start.
To answer your question, I'll assume that this user control is set up with its DataContext pointing to your MainViewModel. The content on the right needs a corresponding property in the main view model i.e. something like this:
private ViewModelBase _CurrentPage;
public ViewModelBase CurrentPage
{
get { return this._CurrentPage; }
set
{
if (this._CurrentPage != value)
{
this._CurrentPage = value;
RaisePropertyChanged(() => this.CurrentPage);
}
}
}
You then create a bunch of "pages" or something that inherit ViewModelBase i.e. Page1ViewModel, Page2ViewModel, SettingsViewModel etc. You then create a ContentControl and bind its content to that property:
<ContentControl Content="{Binding CurrentPage}" />
So now if your view model does something like CurrentPage = new SettingsViewModel() then the ContentControl will be populated with whatever you declared as the DataTemplate for that type (i.e. a control of type views:SettingsView). If you assign the property to something else then the SettingsView will be destroyed and replaced by whatever the DataTemplate for the new type is.
In your example above only SettingsViewModel/SettingsView will work, because that's all you've created a DataTemplate for; in order for this to work you need to create a separate DataTemplate for each ViewModel/View pair type you create.

Cannot display binding on usercontrol?

I'm not able to display a property value on the usercontrol.
I set up the datacontext in this way:
public MainController cm;
public static MainWindow AppWindow;
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
cm = new MainController();
DataContext = cm;
AppWindow = this;
}
}
inside MainController I've all the controller with all the properties like this:
public class MainController: MainControllerVM
{
private ClubController _clubController = new ClubController();
public ClubController ClubController
{
get { return _clubController ; }
}
}
Now I've splitted my user interface in different controls to have more xaml organization. I need to access to the main datacontext that's cm from all user controls, I tried in this way:
public partial class Club : UserControl
{
public Club ()
{
InitializeComponent();
DataContext = MainWindow.AppWindow.cm;
}
but I get:
NullReferenceException
on AppWindow. My main problem's that I can't get to display the value of the property on a label available on the user control:
<Label Content="{Binding ClubController.Club.Name}" />
this binding working in the main window but not working on usercontrol, why??
Suppose you have a window like this:
<Window x:Class="Example.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Example"
Title="MainWindow" Height="350" Width="525">
<UniformGrid Rows="2" Columns="2">
<local:MyUserControlA/>
<local:MyUserControlB/>
<local:MyUserControlC/>
<local:MyUserControlD/>
</UniformGrid>
</Window>
And you set the DataContext in the constructor:
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
Now remember that the DataContext is an inheritable dependency property, i.e. it flows down. (In general, dependency properties are not inheritable by default, unless you explicitly state it)
So, you set the DataContext once on the root of the logical tree (the window) and all of its children will "see" it. (the UniformGrid and the custom controls in our case)
Yes, that means you can directly bind to the view model in your user control's XAML:
<UserControl x:Class="Example.MyUserControlA"
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>
<TextBlock Text="{Binding PropertyFromMainViewModel}"/>
</Grid>
</UserControl>
Now, this approach works well, until your control gets so complicated that it needs to have its own ViewModel and DataContext reespectively.
Usually this happens when the control is not a passive, but maintains a state (validates input, button state, etc.)
1.Declare all properties that you want to bind to the main view model as dependency properties and pay attention to the default value you specify.
2.Locate the main panel of your UserControl and name it, for example "LayoutRoot":
<UserControl x:Class="Example.MyUserControlA"
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 x:Name="LayoutRoot">
<TextBlock Text="{Binding MyDependencyProperty}"/>
</Grid>
</UserControl>
3.Now, you set the DataContext on the LayoutRoot
public MyUserControlA()
{
InitializeComponent();
LayoutRoot.DataContext = new MyUserControlViewModel();
}
4.You bind to the main view model in this way
<Window x:Class="Example.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Example"
Title="MainWindow" Height="350" Width="525">
<UniformGrid Rows="2" Columns="2">
<local:MyUserControlA MyDependencyProperty="{Binding MainViewModelProperty}"/>
<local:MyUserControlB/>
<local:MyUserControlC/>
<local:MyUserControlD/>
</UniformGrid>
</Window>
The other way around is to bind using RelativeSource, but this would break the encapsulation and reusability of your UserControl.
WPF has a steep learning curve, I hope my tips were helpful...

MVVM - Add a Existing User Control in Grid(XAML)

I am developing a Windows 8.1 apps,
and i am following MVVM Pattern
I have a Grid in the Application
<Grid Name="g1">
in which in need to add a existing User Control.
<UserControl
x:Class="CaptureApp.UIComponents.PlayVideo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CaptureApp.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>
<MediaElement Name="MediaPlay" >
</MediaElement>
</Grid>
</UserControl>
Since View (XAML) is not allowed to know the Control.
What will be the correct way to implement it??
the wordpress blog in the comments uses a datatrigger, which isn't present in windows store apps.
if I understand your question correctly, you're trying to have a view within your grid that is conditionally loaded, so that when there is no data for the user control, it is not rendered in the grid?
you could accomplish this by using a
<ContentControl Content="{Binding PropertyOnViewModel}" ContentTemplateSelector="{StaticResource SomeContentTemplateSelector}" />.
public class SomeContentTemplateSelector : DataTemplateSelector
{
public DataTemplate SomeTemplate {get;set;}
protected override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is null)
return null;
return SomeTemplate;
}
}
and then in a DataTemplate, have your UserControl as a child. This will display nothing when there is no Content bound to the ContentControl, and will otherwise display the supplied DataTemplate. You will need to have a property in the over-arching ViewModel that contains the content for this ContentControl, though, just fyi.
edit: if you're adding multiple items dynamically, then you will want an ObservableCollection<> property on your ViewModel, and use an ItemsControl instead of a ContentControl.

Categories

Resources