I'm creating a WPF application using the ModernUI framework and I'm having trouble nesting a ModernMenu control in my MainWindow class. Here's what I had initially for my MainWindow:
<mui:ModernWindow x:Class="MyApp.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:mui="http://firstfloorsoftware.com/ModernUI"
xmlns:local="clr-namespace:MyApp"
mc:Ignorable="d"
Title="MyApp" IsTitleVisible="True" Height="350" Width="525" WindowState="Maximized" ContentSource="/Views/SourcePage1.xaml">
<mui:ModernWindow.MenuLinkGroups >
<mui:LinkGroup x:Name="sourceGroup" DisplayName="Source">
<mui:LinkGroup.Links>
<mui:Link x:Name="sourceLink1" DisplayName="File" Source="/Views/SourcePage1.xaml"/>
<mui:Link x:Name="sourceLink2" DisplayName="Instrumentation" />
</mui:LinkGroup.Links>
</mui:LinkGroup>
</mui:ModernWindow.MenuLinkGroups>
In "SourcePage1.xaml" I try to add a second sub-menu (an instance of ModernMenu):
<UserControl x:Class="MyApp.Views.SourcePage1"
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"
xmlns:local="clr-namespace:MyApp.Views"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="mainGrid" Margin="0,10,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="initialSpacer" Grid.Column="0" Background="Transparent" BorderBrush="DimGray" BorderThickness="2">
<Grid>
<Label Content="Ready" FontSize="40" Foreground="DimGray" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
<GridSplitter Grid.Column="1" Width="4" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
<mui:ModernMenu Grid.Column="2">
<mui:ModernMenu.LinkGroups>
<mui:LinkGroup DisplayName="Catagory1">
<mui:LinkGroup.Links>
<mui:Link x:Name="catagory1Link" DisplayName="name1" Source="/Views/SettingsPage.xaml"/>
<mui:Link DisplayName="insert" />
</mui:LinkGroup.Links>
</mui:LinkGroup>
<mui:LinkGroup DisplayName="Catagory2">
<mui:LinkGroup.Links>
<mui:Link DisplayName="name1" />
<mui:Link DisplayName="name2" />
<mui:Link DisplayName="name3" />
</mui:LinkGroup.Links>
</mui:LinkGroup>
<mui:LinkGroup DisplayName="Catagory3">
<mui:LinkGroup.Links>
<mui:Link DisplayName="name1" />
</mui:LinkGroup.Links>
</mui:LinkGroup>
</mui:ModernMenu.LinkGroups>
</mui:ModernMenu>
</Grid>
Where "SettingsPage.xaml" is just for testing:
<UserControl x:Class="MyApp.Views.SettingsPage"
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"
xmlns:local="clr-namespace:MyApp.Views"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="mainGrid" Margin="0,10,0,0">
<Label Content = "Hi there!"/>
</Grid>
The MainWindows' ModernMenu shows up and works well. Likewise, the ModernMenu on "SourcePage1.xaml" also shows up just fine, but I cannot seem to be able to assign it any source content. When I click on any of the links that have been assigned content (like "catagory1Link") nothing appears. What could be the problem here? Am I not allowed to nest menus like this?
The ModernMenu doesn't auto navigate the frame, as you stated. You could use a ModernTab instead but it will setup another ModernFrame and that frame is the one the links set the source on.
ModernMenu does have a SelectedLink DependencyProperty though. If you bind it to a property on your usercontrol, you can detect the link click and navigate the frame yourself.
SourcePage1.xaml
<mui:ModernMenu Grid.Column="1" SelectedLink="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Path=MenuSelectedLink, Mode=OneWayToSource}">
SourcePage1.xaml.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Controls;
using FirstFloor.ModernUI.Presentation;
namespace WpfApp17
{
public partial class SourcePage1 : UserControl, INotifyPropertyChanged
{
public SourcePage1()
{
InitializeComponent();
}
#region Property Link MenuSelectedLink
private Link _MenuSelectedLink;
public Link MenuSelectedLink { get { return _MenuSelectedLink; } set { SetProperty(ref _MenuSelectedLink, value); OnMenuSelectedLinkChanged(); } }
#endregion
private void OnMenuSelectedLinkChanged()
{
if (MenuSelectedLink == null || MenuSelectedLink.Source == null)
return;
// Navigate the frame to the source.
var frame = FirstFloor.ModernUI.Windows.Navigation.NavigationHelper.FindFrame(null, this);
if (frame != null)
{
if (frame.Source != MenuSelectedLink.Source)
frame.Source = MenuSelectedLink.Source;
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T field, T value, [CallerMemberName]string name = null)
{
if (Equals(field, value))
{
return false;
}
field = value;
this.OnPropertyChanged(name);
return true;
}
protected void OnPropertyChanged([CallerMemberName]string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
#endregion
}
}
J.H.'s solution is correct and I've marked it as such. I only changed things a little to get the behavior I was looking for: I created a new UserControl consisting simply of a "ModernMenu" object in the first row of the grid and a "ModernFrame" in the second row. The frame is named "pageFrame". Then, I just add the content directly to pageFrame when the menu link changes in this new UserControls' code-behind file:
private void OnMenuSelectedLinkChanged()
{
if (MenuSelectedLink == null || MenuSelectedLink.Source == null)
return;
// Navigate the frame to the source.
pageFrame.Source = MenuSelectedLink.Source;
}
Related
Learning WPF Core 3.1 WPF MVVM pattern, using Visual Studio 2019 4.8.04084.
I have a MainWindow with the following (boilerplate excluded)
<Window>
<Grid
Width="1024"
Height="768"
Margin="0,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<usercontrols:CustomerMaintenanceControl
x:Name="CustomerMaintenance"
Grid.Row="0"
Height="109"
VerticalAlignment="Top" />
</Grid>
</Window>
The CustomerMaintenanceControl user control looks like this:
<UserControl
x:Class="Redacted.UserControls.CustomerMaintenanceControl"
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:usercontrols="clr-namespace:Redacted.UserControls"
xmlns:vm="clr-namespace:Redacted.ViewModels"
d:DesignHeight="450"
d:DesignWidth="800"
Loaded="UserControl_Loaded"
mc:Ignorable="d">
<UserControl.Resources>
<vm:CustomerMaintenanceViewModel x:Key="viewModel" />
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<usercontrols:CustomerMaintenanceGridControl
x:Name="gridControl"
Grid.Row="0"
Height="200"
DataContext="{StaticResource viewModel}" />
<usercontrols:CustomerMaintenanceDetailControl
x:Name="detailControl"
Grid.Row="1"
Width="800"
Height="200"
HorizontalAlignment="Left"
VerticalAlignment="Center"
DataContext="{StaticResource viewModel}" />
</Grid>
</UserControl>
Here's the CustomerMaintenanceDetailControl, where the issue is:
<UserControl
x:Class="Redacted.UserControls.CustomerMaintenanceDetailControl"
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:Redacted"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid Margin="0,0,0,325">
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<TabControl
x:Name="tabControl"
Grid.Row="0"
Margin="0,0,0,0">
<TabItem>
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock>General</TextBlock>
</StackPanel>
</TabItem.Header>
<StackPanel>
<TextBox
x:Name="companynmTextbox"
Width="322"
Margin="0,32,228,0"
HorizontalAlignment="Left"
IsReadOnly="True"
Text="{Binding Path=Entity.Companynm}" />
</StackPanel>
</TabItem>
</TabControl>
</Grid>
</UserControl>
So the CustomerMaintenanceControl has two user controls in it, a CustomerMaintenanceGridControl that has a DataGrid and then a CustomerMaintenanceDetailControl which has a tab control and a bound TextBox. The grid is pulling data in fine, so the model and data layer are working. However the 'companyNmTextBox' control on CustomerMaintenanceGridControl is displaying nothing.
There are no binding errors in VS. In addition, when I run the application and open the Live Visual Tree, I can open the properties for 'companyNmTextBox' and under Inherited\DataContext I have my 'Customers' ObservableCollection there and populated, and my 'Entity' property on the model populated with the data for the first Customer. Yet nothing showing onscreen.
Since people are voting to close because of 'debugging details' (?) - the debugging details are in the last paragraph - there are no binding or errors in Visual Studio, and everything appears bound OK in the Live Visual Tree/ The 'desired behaviour' is that the textbox displays the value of the thing that it is bound to. If there are further debugging steps I could investigate I'd be delighted to hear them.
Your Entity has to implement INotifyPropertyChanged interface
public class Entity : INotifyPropertyChanged
{
private string companynm;
public string Companynm
{
get
{
return companynm;
}
set
{
this.companynm = value;
NotifyPropertyChanged();
}
}
...
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Also TextBox companynmTextbox has the property IsReadOnly set to true, so in that case I would modify the binding.
Text="{Binding Path=Entity.Companynm, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
It was a typo to the call to RaisePropertyChanged() in the ViewModel the CustomerMaintenanceDetailControl is using.
I had:
private Customer _entity = new Customer();
public Customer Entity
{
get { return _entity; }
set
{
_entity = value;
RaisePropertyChanged("Customer"); // <- problem here
}
}
I should have had:
private Customer _entity = new Customer();
public Customer Entity
{
get { return _entity; }
set
{
_entity = value;
RaisePropertyChanged("Entity"); // <- doh
}
}
I am trying to change a List that bind to DataGrid from MainWindow (The List is in another class).
How do i do it?
The List contains Tuple with 2 strings and i want to change just the second string when the user enters new values to a textBox in a dialog box (that he open after clicking on a button in the MainWindow.
(At the end i want the user to enter values in this dialog box and then show it in a list in another page (I mean another user control) so im open to hear also about different ways then this list of tuple bind to DataGrid).
How do i change this string from another page (I mean from the MainWindow)?
I tried to use MVVM the problem is that i dont find any connection between the mainWindow and the user control.
Name_List.xaml.cs:
namespace MyApp.Pages.SomeLists
{
public partial class Name_List: UserControl
{
private List<Tuple<string, string>> myNamesList = new List<Tuple<string, string>>();
public Name_List()
{
InitializeComponent();
myNamesList.Add(new Tuple<string, string>("First Name", your_name_bind));
myNamesList.Add(new Tuple<string, string>("Last Name", your_lastName_bind));
NamesGrid.ItemsSource = myNamesList;*/
}
}
}
Name_List.xaml:
<UserControl x:Class="MyApp.Pages.SomeLists.Name_List"
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:MyApp.Pages.SomeLists"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<DataGrid Name="NamesGrid" CanUserReorderColumns="True" CanUserResizeColumns="False" CanUserResizeRows="False" HorizontalAlignment="Left"
GridLinesVisibility="All">
</DataGrid>
</Grid>
</UserControl>
MainWindow.xaml:
<mui:ModernWindow x:Class="MyApp.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="App" IsTitleVisible="True"
Width="1200"
ContentSource="/Pages/Home.xaml">
<mui:ModernWindow.MenuLinkGroups>
<mui:LinkGroup DisplayName="Home page">
<mui:LinkGroup.Links>
<mui:Link DisplayName="home" Source="/Pages/Home.xaml" />
</mui:LinkGroup.Links>
</mui:LinkGroup>
<mui:LinkGroup DisplayName="Lists" >
<mui:LinkGroup.Links>
<mui:Link DisplayName="Open Lists" Source="/Pages/MainLists.xaml" />
</mui:LinkGroup.Links>
</mui:LinkGroup>
<mui:LinkGroup DisplayName="settings" GroupKey="settings">
<mui:LinkGroup.Links>
<mui:Link DisplayName="software" Source="/Pages/SettingsPage.xaml" />
</mui:LinkGroup.Links>
</mui:LinkGroup>
</mui:ModernWindow.MenuLinkGroups>
<mui:ModernWindow.TitleLinks>
<mui:Link x:Name="connect" DisplayName="connect"/>
<mui:Link DisplayName="settings" Source="/Pages/SettingsPage.xaml" />
<mui:Link DisplayName="help" Source="https://github.com" />
</mui:ModernWindow.TitleLinks>
</mui:ModernWindow>
MainWindow.xaml.cs
--There is a long code here... the relevant part is "connect_fun()" function that called after the user click on "OK" in the dialog that opened to him after he clicked on "connect" tab. the dialog contains 2 textBox.--
namespace MyApp
public partial class MainWindow : ModernWindow
{
private string name = "";
private string lastName = "";
//Here i create a Modern dialog in code.
.....
TextBox name_txt = new TextBox();
TextBox lastName_txt = new TextBox();
public MainWindow()
{
InitializeComponent();
}
private void connect_fun(object sender, RoutedEventArgs e)
{
name= name_txt.Text;
lastName = lastName_txt_txt.Text;
}
}
}
MainLists.xaml:
<UserControl x:Class=MyApp.Pages.MainLists"
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"
xmlns:local="clr-namespace:MyApp.Pages"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Pages/Styles/BaseButtonStyle2.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
...
</Grid>
<Grid Style="{StaticResource ContentRoot}" Grid.Row="1">
<mui:ModernTab SelectedSource="/Pages/SomeLists/Name_List.xaml" Layout="Tab" >
<mui:ModernTab.Links>
<mui:Link DisplayName="Name List" Source="/Pages/SomeLists/Name_List.xaml"/>
<mui:Link DisplayName="Cars List" Source="/Pages/SomeLists/Cars_List.xaml"/>
</mui:ModernTab.Links>
</mui:ModernTab>
</Grid>
</Grid>
</UserControl>
I want to bind name and lastName to the dataGrid in Name_List.xaml (it means to your_name_bind and your_lastName_bind in myNamesList in my case).
I am in deep problem since 1 week. Actually, I have one button in MainWindow page say Button1 and one checkbox in Usercontrol page say CheckBox1. So the case is, when I click on Button1 then the CheckBox1 should show as Checked but nothing happening like this. I have Button1_Click method in MainWindow page where I invoked the CheckBox1.IsChecked = true by calling the instance of the UserControl class like
UserControl UC = new UserControl();
UC.CheckBox1.IsChecked =true;
I am posting a demo code for more clarification: This is the waay I want to do
My MainWindow.Xaml Page:
<Window x:Class="MyWpfApplicationDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyWpfApplicationDemo"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button x:Name="btnCheck" Width="110" Height="25" Margin="16,10,165,36" FontWeight="Medium" Click="btnCheck_Click" />
<local:MyUserControlDemo x:Name="MyUserControlDemo" Visibility="Visible" Margin="-54,-49,56,49" />
</Grid>
</Window>
My MainWindow.Xaml.cs page
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnCheck_Click(object sender, RoutedEventArgs e)
{
MyUserControlDemo us = new MyUserControlDemo();
us.chkCheckbox_CheckedChanged(null, null);
}
}
My UserControl.Xaml page
<UserControl x:Class="MyWpfApplicationDemo.MyUserControlDemo"
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>
<CheckBox x:Name="chkCheckbox" Margin="45,0,0,0" Grid.Column="2" Cursor="Hand" Width="100" Height="30" HorizontalAlignment="Center" VerticalAlignment="Center" Checked="chkCheckbox_CheckedChanged" />
</Grid>
</UserControl>
My UserControl.Xaml.cs Page
public partial class MyUserControlDemo : UserControl
{
static int count;
public MyUserControlDemo()
{
InitializeComponent();
}
public void chkCheckbox_CheckedChanged(object sender, RoutedEventArgs e)
{
chkCheckbox.IsChecked = true;
}
}
but after getting the true value the checkbox is not checked and I want to get this done as soon as possible because my project will be delivered after resolving this issue.
Please help me out.
Thanks in advance
If your checkbox and your usercontrol are in the same window just go to the parent of user control that is grid (probably), then go to the parent of grid that is MainWindow(probably) and set chkCheckbox.IsChecked = true;
example:
public void chkCheckbox_CheckedChanged(object sender, RoutedEventArgs e)
{
var grid = this.Parent as Grid;
if(grid != null)
{
var mainWindow = grid.Parent as MainWindow;
if(mainWindow != null)
{
mainWindow.chkCheckbox.IsChecked = true;
}
}
}
UPD:
<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"
x:Name="Main"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:UserControl1 Tag="{Binding ElementName=Main}"/>
<CheckBox Content="IsChecked?" x:Name="chkBox"/>
</Grid>
</Window>
private void Button_Click(object sender, RoutedEventArgs e)
{
var tag = Tag as MainWindow;
if (tag != null)
{
tag.chkBox.IsChecked = true;
}
}
UPD2:
You don't need to create Instance of UserControl in button click event, cuz you've already one in XAML, so you need to use it:
private void btnCheck_Click(object sender, RoutedEventArgs e)
{
MyUserControlDemo.chkCheckbox.IsChecked = true;
}
UPD3
Here's MainWindow XAML code:
<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"
x:Name="Main"
Title="MainWindow" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<local:UserControl1 Tag="{Binding ElementName=Main}"/>
<local:UserControl2 Grid.Column="1" Tag="{Binding ElementName=Main}" x:Name="Control2"/>
</Grid>
</Window>
UserControl1:
<UserControl x:Class="WpfApplication1.UserControl1"
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:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFD3E424" Offset="0"/>
<GradientStop Color="#FF189724" Offset="1"/>
</LinearGradientBrush>
</Grid.Background>
<Button Width="200" Height="50" Content="CLICK ME" Click="Button_Click"/>
</Grid>
</UserControl>
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
/// <summary>
/// Логика взаимодействия для UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var tag = Tag as MainWindow;
if (tag != null)
{
tag.Control2.checkBox.IsChecked = true;
}
}
}
}
UserControl2
<UserControl x:Class="WpfApplication1.UserControl2"
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:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF000CFF" Offset="0"/>
<GradientStop Color="#FF03FF26" Offset="1"/>
</LinearGradientBrush>
</Grid.Background>
<CheckBox x:Name="checkBox" Content="CHECK ME" Foreground="White" FontSize="25" VerticalAlignment="Center" HorizontalAlignment="Center" VerticalContentAlignment="Center"/>
</Grid>
</UserControl>
New programmer question:
I'm trying to create a simple navigation welcome page similiar to wht you whould see on an ipad.
My MainWindow has a titlebar (which wont change) and the rest will be a container of sorts that will show differnt things based on events.
So here is my question how do I bind the container (contentcontrol) to show other views ie show welcomeview originally and then if a user click on a button from the welcome view the content control shows the view they selected.
I currently has the Welcome Page as:
<UserControl x:Class="ContentControl.Views.WelcomeView"
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:vm="clr-namespace:ContentControl.ViewModels"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<vm:WelcomeViewModel />
</UserControl.DataContext>
<Grid Background="red">
<Grid.RowDefinitions >
<RowDefinition Height="25*" />
<RowDefinition Height="50*"/>
<RowDefinition Height="25*"/>
</Grid.RowDefinitions>
<Rectangle Grid.Row="0" Fill="Green"/>
<DockPanel Grid.Row="1" HorizontalAlignment="Center" Background="White">
<Button Height="50" Width="50" Margin="5" Content="DASH" Command="{Binding ViewChangedCommand}" CommandParameter="Dashboard"/>
<Button Height="50" Width="50" Margin="5" Content="ROOM" Command="{Binding ViewChangedCommand}" CommandParameter="MeetingRoom"/>
<Button Height="50" Width="50" Margin="5" Content="SCREEN" Command="{Binding ViewChangedCommand}" CommandParameter="Screen" />
</DockPanel>
<Rectangle Grid.Row="2" Fill="Blue"/>
</Grid>
</UserControl>
The viewModel is as follows:
class WelcomeViewModel : BaseViewModel
{
private MainWindowViewModel _mainWindowVm;
private RelayCommand<string> _viewChangedCommand;
public ICommand ViewChangedCommand
{
get { return _viewChangedCommand ?? (_viewChangedCommand = new RelayCommand<string>(OnViewChanged)); }
}
public event EventHandler ViewChanged;
private void OnViewChanged(string view)
{
EventHandler handler = ViewChanged;
if (handler != null) handler(view, EventArgs.Empty);
}
public MainWindowViewModel MainWindowVm
{
get { return _mainWindowVm; }
set
{
_mainWindowVm = value;
OnPropertyChanged("MainViewModel");
}
}
public WelcomeViewModel()
{
MainWindowVm = new MainWindowViewModel();
ViewChanged += MainWindowVm.ViewChanged;
}
}
}
And I have my Mainwindow as follows:
<Window x:Class="ContentControl.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:ContentControl.ViewModels"
xmlns:views="clr-namespace:ContentControl.Views"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:MainWindowViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type vm:ScreenViewModel}">
<views:ScreenView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:WelcomeViewModel}">
<views:WelcomeView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:MeetingRoomViewModel}">
<views:MeetingRoomView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:DashboardViewModel}">
<views:DashboardView />
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel>
<Label>This Is My Label</Label>
<ContentControl x:Name="MainPanel" Content="{Binding Content, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
MinHeight="200"
MinWidth="200"
HorizontalContentAlignment="Left"
VerticalContentAlignment="Center"
Focusable="False">
</ContentControl>
</StackPanel>
</Grid>
</Window>
Main Window View Model:
class MainWindowViewModel : BaseViewModel
{
private UserControl _content;
public UserControl Content
{
get { return _content; }
set
{
_content = value;
OnPropertyChanged("Content");
}
}
public void ViewChanged(object o, EventArgs e)
{
switch (o.ToString())
{
case "Welcome":
{
var welcome = new WelcomeView();
Content = welcome;
break;
}
case "MeetingRoom":
{
var meetingRoom = new MeetingRoomView();
Content= meetingRoom;
break;
}
case "Dashboard":
{
var dashboard = new DashboardView();
Content = dashboard;
break;
}
case "Screen":
{
var screen = new ScreenView();
Content = screen;
break;
}
}
MessageBox.Show(o.ToString());
}
public MainWindowViewModel()
{
}
}
}
How do I hook these Up to work with each other So I can show the WelcomeView as the content of the contentcontrol and then when I press a button have the ContentControl change to what was selected.
Again sorry I am new to MVVM and WPF and these binding are messing with my head.
The Buttons DASH, ROOM, SCREEN, should be on the MainWindow. The ViewChangedCommand should be on the MainWindowViewModel. And the content will be showed by dynamic templating.
If you want the buttons on the controls:
Ok so, then let's put the buttons on the controls, but the change content command should be in the MainWindowViewModel. To make a binding like this you should do something like this:
Command="{Binding Path=DataContext.ChangeContentCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
in your buttons
I amsomewhat new to Silverlight, What I want to do is to show the Title in the accordion control which is bound from the property of that user control. I have a TextBlock which is inside the DataTemplate of an Accordion control in Silverlight. When I run the application, text is coming blank and nothing is displayed in the Accordion title.
<UserControl x:Class="SilverlightApplication1.SilverlightControl1"
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:layoutToolkit="clr- namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid x:Name="LayoutRoot" Background="White">
<layoutToolkit:Accordion x:Name="accordionFilter" HorizontalAlignment="Stretch" SelectionMode="ZeroOrMore">
<layoutToolkit:AccordionItem MinHeight="0" MaxHeight="120" IsSelected="True">
<layoutToolkit:AccordionItem.HeaderTemplate>
<DataTemplate>
<Grid Height="22" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock
Text="{Binding MainPageSelectedText}"
Width="150"></TextBlock>
</Grid>
</DataTemplate>
</layoutToolkit:AccordionItem.HeaderTemplate>
</layoutToolkit:AccordionItem>
</layoutToolkit:Accordion>
</Grid>
</UserControl>
using System;
using System.ComponentModel;
using System.Windows.Controls;
namespace SilverlightApplication1
{
public partial class SilverlightControl1 : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
PropertyChangedEventHandler ph = this.PropertyChanged;
if (ph != null)
ph(this, new PropertyChangedEventArgs(name));
}
public SilverlightControl1()
{
InitializeComponent();
MainPageSelectedText = "Sample Text";
}
public string MainPageSelectedText
{
get { return _MainPageSelectedText; }
set
{
string myValue = value ?? String.Empty;
if (_MainPageSelectedText != myValue)
{
_MainPageSelectedText = value;
OnPropertyChanged("MainPageSelectedText");
}
}
}
private string _MainPageSelectedText;
}
}
On your data template level you don't have direct access to the user control's DataContext so your binding should look sth like:
Text="{Binding MainPageSelectedText, ElementName=MyUserControl}"
assuming that you will set Name/x:Name of your user control to MyUserControl.