New UserControl not showing up - c#

I have UserControl called "LinqView" where I have menu with buttons.
After user click button I want to display new UserControl using MVVM.
I have created new model class called "UsersModel" and new UserControl called "ViewUsersUserControl".
But I don't know why is not working.
Below is my xaml & cs code.
LinqView.xaml
<UserControl x:Class="LayoutMVVM.Views.LinqView"
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:LayoutMVVM.Views"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
xmlns:veiwmodels="clr-namespace:LayoutMVVM.ViewModels.MojeDBModel"
xmlns:views="clr-namespace:LayoutMVVM.Views.MojeDBViews" >
<UserControl.Resources>
<DataTemplate x:Name="UsersTemp" DataType="{x:Type veiwmodels:UsersModel}">
<views:ViewUsersUserControl DataContext="{Binding}" />
</DataTemplate>
</UserControl.Resources>
<Grid Background="LemonChiffon">
<Menu Height="32" Name="Menu" VerticalAlignment="Top">
<MenuItem Header="_Menu">
<MenuItem Header="Add User" Click="MenuItem_VU" />
</MenuItem>
</Menu>
</Grid>
</UserControl>
LinqView.cs
private void MenuItem_VU(object sender, RoutedEventArgs e)
{
DataContext = new UsersModel();
}

Tried like this?
<UserControl x:Class="LayoutMVVM.Views.LinqView"
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:LayoutMVVM.Views"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
xmlns:veiwmodels="clr-namespace:LayoutMVVM.ViewModels.MojeDBModel"
xmlns:views="clr-namespace:LayoutMVVM.Views.MojeDBViews" >
<UserControl.Resources>
<DataTemplate DataType="{x:Type veiwmodels:UsersModel}">
<views:ViewUsersUserControl DataContext="{Binding}" />
</DataTemplate>
</UserControl.Resources>
<Grid Background="LemonChiffon">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Menu " Height="32" Name="Menu" VerticalAlignment="Top">
<MenuItem Header="_Menu">
<MenuItem Header="Add User" Click="MenuItem_VU" />
</MenuItem>
</Menu>
<ContentControl Grid.Row="1" Content="{Binding UsersModel}"/>
</Grid>
</UserControl>
and your C# class should look like,
public class MainViewModel
{
public UsersModel UsersModel {get;set;}
// other properties
}
and in menu click,
private void MenuItem_VU(object sender, RoutedEventArgs e)
{
DataContext = new MainViewModel();
}
i have removed key on DataTemplate.
Update:
Simple working sample,
MainWindow.cs
namespace WpfApplication29
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
}
public class MainViewModel : INotifyPropertyChanged
{
public LinqViewModel LinqModel
{
get; set;
} = new LinqViewModel();
public MainViewModel()
{
SelectedMainModel = LinqModel;
}
private object selectedModel;
public object SelectedMainModel
{
get
{
return selectedModel;
}
set
{
selectedModel = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void Notify(string name)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public class LinqViewModel : INotifyPropertyChanged
{
public UserModel UserModel
{
get; set;
} = new UserModel();
private object selectedChildModel;
public object SelectedChildModel
{
get
{
return selectedChildModel;
}
set
{
selectedChildModel = value;
Notify("SelectedChildModel");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void Notify(string name)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public class UserModel
{
}
}
MainWindow.xaml
<Window
x:Class="WpfApplication29.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:local="clr-namespace:WpfApplication29"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="525"
Height="350"
mc:Ignorable="d">
<Window.Resources>
<DataTemplate DataType="{x:Type local:LinqViewModel}">
<local:LinqView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:UserModel}">
<local:UserView />
</DataTemplate>
</Window.Resources>
<Grid>
<ContentControl Content="{Binding SelectedMainModel}" />
</Grid>
</Window>
User UserControl
<UserControl
x:Class="WpfApplication29.UserView"
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:local="clr-namespace:WpfApplication29"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<Grid >
<TextBlock Text="From UserView"/>
</Grid>
</UserControl>
LinqView Usercontrol xaml
<UserControl
x:Class="WpfApplication29.LinqView"
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:local="clr-namespace:WpfApplication29"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<Grid Background="LemonChiffon">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Menu Height="32" Name="Menu" VerticalAlignment="Top">
<MenuItem Header="_Menu">
<MenuItem Header="Add User" Click="MenuItem_VU" />
</MenuItem>
</Menu>
<ContentControl Grid.Row="1" Content="{Binding SelectedChildModel}"/>
</Grid>
</UserControl>
Linqview usercontrol cs
namespace WpfApplication29
{
/// <summary>
/// Interaction logic for LinqView.xaml
/// </summary>
public partial class LinqView : UserControl
{
public LinqView()
{
InitializeComponent();
}
private void MenuItem_VU(object sender, RoutedEventArgs e)
{
(this.DataContext as LinqViewModel).SelectedChildModel = (this.DataContext as LinqViewModel).UserModel;
}
}
}
this sample follows multilevel hierarchy. hope this helps.

If you have only one UsersModel you dont need to have it as resource template:
<UserControl x:Class="LayoutMVVM.Views.LinqView"
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:LayoutMVVM.Views"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
xmlns:veiwmodels="clr-namespace:LayoutMVVM.ViewModels.MojeDBModel"
xmlns:views="clr-namespace:LayoutMVVM.Views.MojeDBViews" >
<DockPanel Background="LemonChiffon">
<Menu Height="32" Name="Menu" DockPanel.Dock="Top">
<MenuItem Header="_Menu">
<MenuItem Header="Add User" />
</MenuItem>
</Menu>
<views:ViewUsersUserControl />
</DockPanel>
</UserControl>

Related

Page doesn't retain UI changes in multi-page WPF/MVVM application

I have a simple multi-page MVVM Light application, my issue is that if I draw something on the screen or change the background color of a button in one of the views/pages then go to a different page and come back, the drawn content is no longer there.
MAIN PAGE CODE:
XAML
<Window x:Class="TwoViews.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"
Title="MVVM Light View Switching"
d:DesignHeight="300"
d:DesignWidth="300"
DataContext="{Binding Main,
Source={StaticResource Locator}}"
ResizeMode="NoResize"
SizeToContent="WidthAndHeight"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentControl Content="{Binding CurrentViewModel}" />
<DockPanel Grid.Row="1" Margin="5">
<Button Width="75"
Height="23"
Command="{Binding SecondViewCommand}"
Content="Second View"
DockPanel.Dock="Right" />
<Button Width="75"
Height="23"
Command="{Binding FirstViewCommand}"
Content="First View"
DockPanel.Dock="Left" />
</DockPanel>
</Grid>
</Window>
ViewModel
using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
namespace TwoViews.ViewModels
{
public class MainViewModel : ViewModelBase
{
private ViewModelBase _currentViewModel;
readonly static SecondViewModel _secondViewModel = new SecondViewModel();
readonly static FirstViewModel _firstViewModel = new FirstViewModel();
public ViewModelBase CurrentViewModel
{
get
{
return _currentViewModel;
}
set
{
if (_currentViewModel == value)
return;
_currentViewModel = value;
RaisePropertyChanged("CurrentViewModel");
}
}
public ICommand FirstViewCommand { get; private set; }
public ICommand SecondViewCommand { get; private set; }
public MainViewModel()
{
CurrentViewModel = MainViewModel._firstViewModel;
FirstViewCommand = new RelayCommand(() => ExecuteFirstViewCommand());
SecondViewCommand = new RelayCommand(() => ExecuteSecondViewCommand());
}
private void ExecuteFirstViewCommand()
{
CurrentViewModel = MainViewModel._firstViewModel;
}
private void ExecuteSecondViewCommand()
{
CurrentViewModel = MainViewModel._secondViewModel;
}
}
}
Codebehind
namespace TwoViews
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
FIRST PAGE CODE:
XAML
<UserControl x:Class="TwoViews.Views.FirstView"
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"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<Grid>
<Label x:Name="label" Content="First Page" HorizontalAlignment="Left" Margin="92,46,0,0" VerticalAlignment="Top"/>
</Grid>
</UserControl>
ViewModel
namespace TwoViews.ViewModels
{
public class FirstViewModel : ViewModelBase
{
public FirstViewModel()
{
}
}
}
Codebehind
namespace TwoViews.Views
{
public partial class FirstView : UserControl
{
public FirstView()
{
InitializeComponent();
}
}
}
SECOND PAGE CODE
XAML
<UserControl x:Class="TwoViews.Views.SecondView"
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"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<Grid Name="myGrid">
<Grid Name="GridSecondPage" HorizontalAlignment="Left" Height="107" Margin="10,43,0,0" VerticalAlignment="Top" Width="280"/>
<Button x:Name="DrawRectangle" Content="Draw" HorizontalAlignment="Left" Margin="135,203,0,0" VerticalAlignment="Top" Width="75" Click="DrawRectangle_Click"/>
</Grid>
</UserControl>
ViewModel
namespace TwoViews.ViewModels
{
public class SecondViewModel : ViewModelBase
{
}
}
Codebehind
namespace TwoViews.Views
{
public partial class SecondView : UserControl
{
public SecondView()
{
InitializeComponent();
}
private void DrawRectangle_Click(object sender, RoutedEventArgs e)
{
Rectangle myRectangle = new Rectangle();
myRectangle.Name = "myRectangle";
myRectangle.Width = 100;
myRectangle.Height = 100;
myRectangle.Fill = Brushes.Blue;
GridSecondPage.Children.Add(myRectangle);
}
}
}

Why the first launch of my WPF application shows the class name of a ViewModel instead of its content (properties)?

I bind a MainWindowViewModel to the DataContext of a MainWindow.
Then I initialize this MainWindowViewModel to a specific itemsPageViewModel.
The problem is that on startUp I see itemsPageViewModel 's class name instead of its content:
Startup
However, after switching pages through buttons (RelayCommands), the same ViewModel now shows its content:
PageSwitched
Both operations pass through the same code-line:
CurrentPageViewModel = _itemsPageViewModel
How can it produce different results?
CODE
MainWindow.xaml
<Window x:Class="ListItemUI.Views.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"
mc:Ignorable="d"
Title="ListItemUI" Height="400" Width="600">
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="10"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<StackPanel Orientation="Horizontal">
<Button Content="ITEMS" Margin="2" Command ="{Binding SelectItemsPageViewModel}"></Button>
<Button Content="HELP" Margin="2" Command ="{Binding SelectInfoPageViewModel}"></Button>
</StackPanel>
</Grid>
<ContentControl Grid.Row="2" Content="{Binding CurrentPageViewModel}"/>
</Grid>
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
using ListItemUI.InfoPage.ViewModels;
using ListItemUI.ListItemPage.ViewModels;
using ListItemUI.ViewModels;
namespace ListItemUI.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow(IPageFactory itemPageFactory, IPageFactory infoPageFactory)
{
InitializeComponent();
var mainWindowVM = new MainWindowViewModel(itemPageFactory,infoPageFactory);
DataContext = mainWindowVM;
}
}
}
MainWindowViewModel.cs
using System;
using System.Windows.Input;
using ListItemUI.ListItemPage.ViewModels;
namespace ListItemUI.ViewModels
{
public class MainWindowViewModel : ViewModelBase
{
private readonly IListItemUIViewModel _itemsPageViewModel;
private readonly IListItemUIViewModel _infoPageViewModel;
public ICommand SelectItemsPageViewModel { get; }
public ICommand SelectInfoPageViewModel { get; }
public object CurrentPageViewModel
{
get { return _currentPageViewModel; }
set
{
_currentPageViewModel = value;
RaisePropertyChanged(() => CurrentPageViewModel);
}
}
private object _currentPageViewModel;
public MainWindowViewModel(IPageFactory itemsPageFactory, IPageFactory infoPageFactory)
{
_itemsPageViewModel = itemsPageFactory.CreatePage();
_infoPageViewModel = infoPageFactory.CreatePage();
SelectItemsPageViewModel = new RelayCommand(_ =>
{
CurrentPageViewModel = _itemsPageViewModel;
});
SelectInfoPageViewModel = new RelayCommand(_ =>
{
CurrentPageViewModel = _infoPageViewModel;
});
CurrentPageViewModel = _itemsPageViewModel;
}
}
}
ListItemPage.xaml (dataTemplates)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels ="clr-namespace:ListItemUI.ListItemPage.ViewModels">
<DataTemplate DataType="{x:Type viewModels:ItemViewModel}">
<StackPanel>
<TextBlock Foreground="RoyalBlue" FontWeight="Bold" Text="{Binding Path=ItemViewDescription, StringFormat='Group Info = {0}'}"></TextBlock>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:ItemsPageViewModel}">
<StackPanel>
<TextBlock Text ="{Binding Path=Title}"></TextBlock>
<Grid Grid.Column="0" Background="Aquamarine">
<ListBox ItemsSource="{Binding Path=LocalItemViewModels}" Margin="5">
</ListBox>
</Grid>
</StackPanel>
</DataTemplate>
</ResourceDictionary>
App.xaml
<Application x:Class="ListItemUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ListItemPage/Views/ListItemPage.xaml"></ResourceDictionary>
<ResourceDictionary Source="InfoPage/Views/InfoView.xaml"></ResourceDictionary>
<!--GLOBAL RESOURCES -->
<ResourceDictionary Source="Views/GlobalResources.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
We used a workaround to solve this specific problem.
We chose not to use resource dictionaries, putting the dataTemplates of the viewModels directly into the mainwindow.xaml: now everything works.
Something strange happens when we use resource dictionaries.

WPF data binding through UserControls

I would like to bind property from the main window's DataContext, above you can see my UserControls and models. So I want to bind the Model.ID.Label1 and Model.ID.Label2 properties to the main_id/card_1/top and main_id/card_1/bottom controls. I hope it's clear. If I enable the
ref_lbl Label it will shows the "lbl1", the card_2 still working with the hardcoded texts but the card_1 will be blank. What should I modify to fix the binding on card_1?
I have an ID UserControl and it contains another UserControl.
XAML:
<UserControl x:Class="stack.ID"
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:Controls="clr-namespace:stack.Controls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Label Name="ref_lbl" Grid.Row="0" Content="{Binding Label1}" Visibility="Collapsed" />
<Controls:Card x:Name="card_1" Grid.Row="0" TopLabel="{Binding Label1}" BottomLabel="{Binding Label2}" />
<Controls:Card x:Name="card_2" Grid.Row="1" TopLabel="Text 1" BottomLabel="Text 2" />
</Grid>
Code Behind: default, auto generated
Here is the Card UserControl.
XAML:
<UserControl x:Class="stack.Controls.Card"
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" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Label Grid.Row="0" FontSize="20" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding TopLabel}" />
<Label Grid.Row="1" FontSize="20" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding BottomLabel}" />
</Grid>
Code Behind:
namespace stack.Controls
{
public partial class Card : UserControl
{
public static readonly DependencyProperty TopLabelProperty = DependencyProperty.Register("TopLabel", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
public static readonly DependencyProperty BottomLabelProperty = DependencyProperty.Register("BottomLabel", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
public Card()
{
InitializeComponent();
}
public string TopLabel
{
get
{
return (string)GetValue(TopLabelProperty);
}
set
{
SetValue(TopLabelProperty, value);
}
}
public string BottomLabel
{
get
{
return (string)GetValue(BottomLabelProperty);
}
set
{
SetValue(BottomLabelProperty, value);
}
}
}
}
And here is my main window.
XAML:
<Window x:Class="stack.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:stack"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:Model />
</Window.DataContext>
<Grid>
<local:ID x:Name="main_id" DataContext="{Binding ID}" />
</Grid>
Code Behind: default, auto generated
And I also have 2 models.
namespace stack
{
public class IDModel
{
private string label1 = "lbl1";
private string label2 = "lbl2";
public string Label1
{
get
{
return label1;
}
set
{
label1 = value;
}
}
public string Label2
{
get
{
return label2;
}
set
{
label2 = value;
}
}
}
public class Model
{
private IDModel id = new IDModel();
public IDModel ID
{
get
{
return id;
}
set
{
id = value;
}
}
}
}
Remove
DataContext="{Binding RelativeSource={RelativeSource Self}}"
from the Card's XAML.
It prevents inheriting the DataContext from its parent ID control, which is necessary when you write
<Controls:Card ... TopLabel="{Binding Label1}" />
Instead write the Content bindings in Card's XAML like this:
<Label ... Content="{Binding TopLabel,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" />

CommandParameter is always NULL

I want to implement a simple Close Button in a WPF Window. The Window basically looks like this:
<Window x:Class="MyApplication.MainWindow"
xmlns=""....
...."
Title="MainWindow" WindowState="Maximized" WindowStartupLocation="CenterScreen" x:Name="mainWindow">
<DockPanel LastChildFill="True">
<Ribbon DockPanel.Dock="Top">
<Ribbon.ApplicationMenu>
<RibbonApplicationMenu SmallImageSource="Resources/menu_16x16.png">
<RibbonApplicationMenu.FooterPaneContent>
<RibbonButton Label="Beenden"
Command="{Binding CmdCloseApp}"
CommandParameter="{Binding ElementName=mainWindow}"
SmallImageSource="Resources/ende_16x16.png"
HorizontalAlignment="Right"/>
</RibbonApplicationMenu.FooterPaneContent>
</RibbonApplicationMenu>
</Ribbon.ApplicationMenu>
</Ribbon>
</DockPanel>
</Window>
DataContext of this Window ist set in it's Code-behindt to an instance of MainWindowViewModel
MainWindowViewModel:
public class MainWindowViewModel
{
public ICommand CmdCloseApp { get; set; }
public MainWindowViewModel()
{
CmdCloseApp = new RelayCommand<Window>(CloseApp);
}
public void CloseApp(Window w)
{
w.Close();
}
}
In CloseAppw is always null. Alle the other commands with string paramters, etc.. work perfectly - my only problem is that i don't get the window element does not find a way to my viewmodel.
thanks for your help!
EDIT
I am so sorry, i tried it with a simple button and it worked - The problem only occurs with RibbonButton
Edit: After your change to application menu RibbonButton your issue is that Microsoft RibbonControlLibrary uses a popup menu to hold the button, and the MainWindow is not part (parent of) of the popup menu's visual tree, so your ElementName binding can not find the "mainWindow" window, so it assigns null to CommandParameter
You could use static Application.Current to get MainWindow, then it will work.
NB! MainWindow is the Application property name, not the name of your window
<Window x:Class="WpfRelayCommandParameter.MainWindow"
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:wpfRelayCommandParameter="clr-namespace:WpfRelayCommandParameter"
xmlns:ribbon="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance wpfRelayCommandParameter:MainWindowViewModel}"
Title="MainWindow" Height="350" Width="525"
x:Name="mainWindow">
<DockPanel LastChildFill="True">
<DockPanel LastChildFill="True">
<ribbon:Ribbon DockPanel.Dock="Top">
<ribbon:Ribbon.ApplicationMenu>
<ribbon:RibbonApplicationMenu SmallImageSource="Resources/AppMenu.png">
<ribbon:RibbonApplicationMenu.FooterPaneContent>
<ribbon:RibbonButton Label="Beenden"
Command="{Binding CmdCloseApp}"
CommandParameter="{Binding MainWindow, Source={x:Static Application.Current}}"
SmallImageSource="Resources/Exit.png"
HorizontalAlignment="Right" Click="ButtonBase_OnClick"/>
</ribbon:RibbonApplicationMenu.FooterPaneContent>
</ribbon:RibbonApplicationMenu>
</ribbon:Ribbon.ApplicationMenu>
</ribbon:Ribbon>
</DockPanel>
</DockPanel>
Personally I prefer callbacks to the window to go through an interface that can be custom to your view model needs, and can be mocked in unit tests:
<Window x:Class="WpfRelayCommandParameter.MainWindow"
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:wpfRelayCommandParameter="clr-namespace:WpfRelayCommandParameter"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance wpfRelayCommandParameter:MainWindowViewModel}"
Title="MainWindow" Height="350" Width="525"
x:Name="mainWindow">
<Grid>
<Button Content="Close Window"
Command="{Binding CmdCloseApp}"
VerticalAlignment="Top"
HorizontalAlignment="Left" />
</Grid>
Code
public partial class MainWindow : Window, IMainWindow
{
public MainWindow()
{
DataContext = new MainWindowViewModel(this);
InitializeComponent();
}
}
public interface IMainWindow
{
void Close();
}
public class MainWindowViewModel
{
private readonly IMainWindow _mainWindow;
public MainWindowViewModel() : this(null)
{
// Design time
}
public MainWindowViewModel(IMainWindow mainWindow)
{
_mainWindow = mainWindow;
CmdCloseApp = new RelayCommand(CloseApp);
}
public ICommand CmdCloseApp { get; set; }
public void CloseApp(object parameter)
{
_mainWindow.Close();
}
}
Note possible issues with type and null for CanExecute CanExecute on RelayCommand

How to instantiate UserControl and add Items to its Container in XAML

I have the following UserControl:
<UserControl x:Class="UserControlTest.UserControl"
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">
<StackPanel x:Name="MainPanel" Background="White">
<TextBlock Text="BasePanel"/>
</StackPanel>
And my MainWindwo.XAML:
<Window x:Class="UserControlTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:UC="clr-namespace:UserControlTest"
Title="MainWindow" Height="350" Width="525">
<DockPanel Name="dpMain">
<UC:Control x:Name="ucBaseControl" />
</DockPanel>
In the code-behind MainWindow.xaml.cs:
namespace UserControlTest
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TextBox tbWorld = new TextBox();
tbWorld.Text = "Hello World";
ucBaseControl.MainPanel.Children.Add(tbWorld);
}
}
}
Is there a way to achieve this in XAML to avoid code-behind?
Thank you very much in advance!
You could try to do something like:
XAML:
<UserControl x:Class="WpfApplication1.BaseControl"
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">
<StackPanel x:Name="root">
<TextBlock>I'm from base</TextBlock>
<StackPanel x:Name="newPanel">
</StackPanel>
</StackPanel>
</UserControl>
Code behind:
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
namespace WpfApplication1
{
[ContentProperty("NewControls")]
public partial class BaseControl : UserControl
{
public UIElementCollection NewControls
{
get { return (UIElementCollection)GetValue(NewControlsProperty); }
set { SetValue(NewControlsProperty, value); }
}
public static readonly DependencyProperty NewControlsProperty = DependencyProperty.Register("NewControls", typeof(UIElementCollection), typeof(BaseControl));
public BaseControl()
{
InitializeComponent();
this.NewControls = new UIElementCollection(this, this);
this.Loaded += BaseControl_Loaded;
}
void BaseControl_Loaded(object sender, RoutedEventArgs e)
{
foreach (UIElement element in NewControls.Cast<UIElement>().ToList())
{
NewControls.Remove(element);
this.newPanel.Children.Add(element);
}
}
}
}
And in the other control or window:
xmlns:local="clr-namespace:WpfApplication1"
...
<local:BaseControl>
<TextBlock>I'm from new</TextBlock>
</local:BaseControl>
Not sure it perfectly fits your needs but may serve as a good base.
Here my solution.
My UserControl:
<UserControl x:Class="ucFancyMenu" x:Name="MySelf"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Label Height="30" VerticalAlignment="Top" Background="#F0F">So Fancy</Label>
<ItemsControl Margin="0 30 0 0" ItemsSource="{Binding ElementName=MySelf, Path=Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</UserControl>
The UserControl Class:
<Markup.ContentProperty("Items")> _
Public Class ucFancyMenu
Public Property Items As New List(Of UIElement)
End Class
How to use it in other Xamls:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<local:ucFancyMenu>
<Button>FancyBtn 1</Button>
<Button>FancyBtn 2</Button>
<Button>FancyBtn 3</Button>
<Button>FancyBtn 4</Button>
<Button>FancyBtn 5</Button>
<Button>FancyBtn 6</Button>
<Button>FancyBtn 7</Button>
</local:ucFancyMenu>
</Grid>
</Window>

Categories